Alexander
Alexander

Reputation: 1378

extracting array inside an object thats inside an array

hi guys I'm trying to extract data from this:

1) […]
​
0: {…}
​​
__v: 0
​​
_id: "5ba96b8ebffd923734090df4"
​​
formID: "5ba96b83bffd923734090df0"
​​
inputArr: Array(3) [ "value1", "value2", "value3" ]
​​
labelArr: Array(3) [ "label1", "label2", "label3" ]
​​
<prototype>: Object { … }
​
length: 1
​
<prototype>: Array []

I need to get to the array inside the data, which is this.state.inputData (what you see above is the content),

I tried

const labels = inputDataArr[0].labelArr.map((r, index) => {
      return (
        <tr key={index}>
          <th>{index}</th>
          <th>{r[index]}</th>
        </tr>
      );

but I get item undefined, anybody knows why?

EDIT : additional problem rendering :

renderData(i) {
    const { inputDataArr } = this.state;
    return (
      !!inputDataArr.length &&
      inputDataArr[i].inputArr.map((input, index) => (
        <th key={index}>{input}</th>
      ))
    );
  }
  countLength() {
    const { inputDataArr } = this.state;
    return !!inputDataArr.length && inputDataArr[0].inputArr.length;
  }
  runThrough() {
    for (let i = 0; i < this.countLength; i++) return this.renderData(i);
  }
  render() {
    const data = this.runThrough();
    return (
      <div className="app">
        <table>
          <tr>{this.renderLabels()}</tr>
          {data}
        </table>
      </div>
    );
  }
}

Upvotes: 0

Views: 88

Answers (1)

devserkan
devserkan

Reputation: 17638

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>
    ));
  }
}

Upvotes: 1

Related Questions