user11553898
user11553898

Reputation:

How to pass data to props from state?

I'm learning React and have some troubles with using state and props. There is two files: App.js and component. In App.js i use axios to get JSON data from IP and store in a state. But I cannot pass the data to props through the state. Here is App.js:

import React from 'react';
import axios from 'axios';
import Shutruk from './Shutruk';

const qwerty = {
  "data": [
      {
          "_id": "5d1cb18e4af03042df6267c5",
          "title": "Shutruk",
          "description": "Shhhhhhhhhhhhh",
          "date": "2019-07-03T13:45:50.850Z",
          "__v": 0
      },
      {
          "_id": "5d1cc27b37c9751001f5c12f",
          "title": "Shilkhak",
          "description": "Shilkhak-Inshushinak",
          "date": "2019-07-03T14:58:03.797Z",
          "__v": 0
      },
      {
          "_id": "5d1cc45655780f11112a023f",
          "title": "Унташ",
          "description": "Untash-Napirisha",
          "date": "2019-07-03T15:05:58.699Z",
          "__v": 0
      },
      {
          "_id": "5d1ef36c503601183b5f856f",
          "title": "dgfdgfdhgf",
          "description": "bbbbbbbbbbbbbbbbb",
          "date": "2019-07-05T06:51:24.873Z",
          "__v": 0
      },
      {
          "_id": "5d1ef381503601183b5f8570",
          "title": "qewytuytruytru",
          "description": "jhfgasjdfgasjdfgjhsdf",
          "date": "2019-07-05T06:51:45.761Z",
          "__v": 0
      }
  ]
};
class App extends React.Component {
  state = {
    data: []
  }
  componentDidMount() {
    axios.get('http://localhost:5555/posts')
      .then(res => {
        const data = res.data;
        this.setState({ data });
      })
  }
  render() {
    return (
      <div>
        <Shutruk name={ this.state.data.data[0].title }/>
      </div>
    )
  }
}
export default App;

Here is the component:

import React from 'react';

class Shutruk extends React.Component {
  render() {
    return (
      <div>
        <h1>This is is {this.props.name}!</h1>
      </div>
    )
  }
}

export default Shutruk;

I use axios to get data from backend, but when I insert it to props, it does'nt work. I create an array qwerty[] with the same data, and when I replace with:

return (
  <div>
    <Shutruk name={ qwerty.data[0].title }/>
  </div>
)

it works correctly. What is the problem, if there is no difference between 'this.state.data' and 'qwerty'? I checked with console.log and the result is same! Thanks to everyone for any help!

Upvotes: 0

Views: 1717

Answers (3)

ravibagul91
ravibagul91

Reputation: 20755

Just change this,

<Shutruk name={ this.state.data.data[0].title }/>

with,

{this.state.data ? <Shutruk name={ this.state.data[0].title }/> : null}

Update

If you are not getting data, then you must use async/await,

async componentDidMount() {
    await axios.get('http://localhost:5555/posts')
      .then(res => {
        //console.log(res) => if `res` is {data:[...]} , then do this,
        const data = res.data;
        //console.log(res) => if `res` is {data: data: [...]} , then do this,
        const data = res.data.data;
        this.setState({ data });
      })
  }

Upvotes: 0

Dyo
Dyo

Reputation: 4464

Your App component is probably crashing when mounting while you're accessing an undefined state because your try to get this.state.data.data[0].title when data state equals []

Try replacing your App component like this to prevent access to an undefined state (I recommend doing this for all your asynchronous operations in the components):

class App extends React.Component {
  state = {
    data: [],
    loading: true,
    error: false,
  }
  componentDidMount() {
    axios.get('http://localhost:5555/posts')
      .then(res => {
        const data = res.data.data; // get the data array instead of object
        this.setState({ data, loading: false });
      })
      .catch(err => { // log request error and prevent access to undefined state
        this.setState({ loading: false, error: true });
        console.error(err); 
  }
  render() {
    if (this.state.loading) {
      return(
        <div>
          <p> Loading... </p>
        </div>
      )
    }
    if (this.state.error || !this.state.data[0]) { // if request failed or data is empty don't try to access it either
      return(
        <div>
          <p> An error occurred </p>
        </div>
      )
    }
    return (
      <div>
        <Shutruk name={ this.state.data[0].title }/> // access to data array state
      </div>
    )
  }
}
export default App;

Upvotes: 0

Sharath Kumar
Sharath Kumar

Reputation: 290

This is because, axios and setState are asynchronous and when the component loads in componentDidMount, it takes a while to load data into state and since data.data[0] is still empty, it doesn't work. But when you use a const to declare it, it works as it is already present.

Instead of

<Shutruk name={ this.state.data.data[0].title }/>

Do:

  renderShutruk = () => {
    if (this.state.data.data !== undefined) {
      return <Shutruk name={this.state.data.data[0].title} />
    } else {
      return null;
    }
  };

  render() {
    return (
      <div>
        {this.renderShutruk()}
      </div>
    );
  }

Upvotes: 0

Related Questions