React - Passing fetched data from API as props to components

Viewed 19469

Iam trying to understand and learn how to pass around data as props to other components to use. Iam trying to build a top-level hierarchy where the API Request is made in a class at top level and then the result is passed around to child components to be used as props and then in states.

The problem is that when i pass the result i get "Object Promise" in my child component. How do I access the data sent as props to child components?

As you can see in my App.js in my render() method that i created a component of the class API and pass the result from the fetchData() method as parameter to the component.

In my API.js class i used console.log to check the result but the result i get from the logs are:

line 5: {dataObject: Promise}

line 10: undefined

App.js:

import API from './API';

class App extends Component {

  componentDidMount(){
    this.fetchData();
  }


  fetchData(){
      const url = "https://randomuser.me/api/?results=50&nat=us,dk,fr,gb";
      return fetch(url)
          .then(response => response.json())
          .then(parsedJSON => console.log(parsedJSON.results))
          .catch(error => console.log(error));
  }

  render() {
    return (
      <div className="App">
        <API dataObject={this.fetchData()}/>
      </div>
    );
  }
}

export default App;

API.js

import React from 'react';

class API extends React.Component{
    constructor(props){
        console.log(props);
        super(props);
        this.state = {
            dataObj:props.dataObject
        };
        console.log(this.state.dataObject)
    }


    render() {
        return(
            <p>""</p>
        )
    }
}

export default API;
3 Answers

Try changing App.js to this:

import API from './API';

class App extends Component {

  componentDidMount(){
    this.fetchData();
  }


  fetchData(){
      const url = "https://randomuser.me/api/?results=50&nat=us,dk,fr,gb";
      return fetch(url)
          .then(response => response.json())
          .then(parsedJSON => this.setState({results: parsedJSON.results}))
          .catch(error => console.log(error));
  }

  render() {
    return (
      <div className="App">
        <API dataObject={this.state.results}/>
      </div>
    );
  }
}

export default App;

This makes sure you fetch the data in componentDidMount and it now uses state to store the data which then will be passed into your API component.

If anyone is looking for an answer using Hooks then this might help.

App.js

import API from './API';

function App(props) {

  const [result, setResult] = React.useState({});

  // similar to componentDidMount
  React.useEffect(() => {
    this.fetchData();
  }, []);


  fetchData() {
      const url = "https://randomuser.me/api/?results=50&nat=us,dk,fr,gb";
      fetch(url)
          .then(response => setResult(response.json()))
          .catch(error => console.log(error));
  }
  return (
      <div className="App">
        <API dataObject={result}/>
      </div>
    );
}

export default App;

API.js

import React from "react";

function API(props) {
  
  const [result, setResult] = React.useState(props.dataObject);

  React.useEffect(() => {
    setResult(result);
  }, [result]);

  return <p>{result}</p>;
}

export default API;

Hope it helps! And let me know if anything is incorrect.

You should fetch data in componentDidMount and not in render. Fetching the data within render causes the API request to be repeated, every time the DOM is re-rendered by react.js.

After making the GET request to the API endpoint, first parse the data into a javascript object, then set the results to state using this.setState from within your component.

From there, you may pass the data held in state to child components as props in the render function.

For example:

const App = (props) => 
    <ChildComponent />

class ChildComponent extends React.Component {

    constructor(props){
        super(props);
        this.state = {
            results: []
        }
    }
    componentDidMount(){
        fetch('/api/endpoint')
            .then(res => res.json())
            .then(results => this.setState({results})
    }

    render(){
        return <GrandchildComponent {...this.state} />
    }

}

const GrandchildComponent = (props) => 
    <div>{props.results}</div>
Related