Given the same example from your other question. Not quite sure this suits you as it is, maybe you need to change and think about it a little bit.
class App extends React.Component {
state = {
inputDataArr: [
{
formID: "3",
inputArr: [ "value1", "value2" ],
labelArr: [ "label1", "label2" ],
},
{
formID: "3",
inputArr: [ "value3", "value4" ],
labelArr: [ "label3", "label4" ],
},
],
}
renderLabels() {
const { inputDataArr } = this.state;
return !!inputDataArr.length && inputDataArr[ 0 ].labelArr.map( ( label, index ) =>
( <tr key={label}>
<th>{index}</th>
<th>{label}</th>
</tr> ) );
}
render() {
return (
<div>
<table>
{this.renderLabels()}
</table>
</div>
);
}
}
ReactDOM.render( <App />, document.getElementById( "root" ) );
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Update after comments
After learning that you are getting the data via an async operation, I've added a small condition to the renderLabels method. Now it looks for if the array's length returns true:
return !!inputDataArr.length && inputDataArr[ 0 ]
This is a mix of logical operators and React's rendering logic. Why I use !!inputDataArr.length instead of inputDataArr.length?
Normally, in logical operators, if the first condition is 0 then it does not pass the second part.
const num = 0;
num && console.log( "passed the second part" );
As you can see it never passes the second part. This is because 0 means false here.
React ignores rendering if a value is undefined or false or null. But it renders if a value is 0 :)
Let's see:
class App extends React.Component {
state = {
num: 0,
};
render() {
return (
<div>
{this.state.num && <p>Render me</p>}
</div>
);
}
}
ReactDOM.render( <App />, document.getElementById( "root" ) );
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
This is similar to your situation. In the first render array's length is 0. So, if we use this:
return inputDataArr.length && inputDataArr[ 0 ]
it renders a 0. What we want here is ignore the rendering. So if we use logical NOT operator twice we get a false here and React ignores rendering. Why we get false?
Since 0 means false, !!false again evaluated to false. Then, React ignores rendering and we are safe from the error that you provided in your question.
When the data lands your app, in the second render this time array's length is greater than 0, let's say 2. !!2 evaluates to true then React renders the second part of the condition, your label array.
You can write your condition like this if you want:
renderLabels() {
const { inputDataArr } = this.state;
if (inputDataArr.length > 1) {
return inputDataArr[0].labelArr.map((label, index) => (
<tr key={label}>
<th>{index}</th>
<th>{label}</th>
</tr>
));
}
}
rin your mapping as an array, it is actually one of theinputArrvalues.<th>{r[index]}</th>should be<th>{r}</th>const labels = inputDataArr.labelArrinstead ofinputDataArr[0]incase it is not an array.