1

I am using React-Native and am having issues just getting data to render from an API, into the render function. I'm running node JS and express on one end to pull some data from a SQL database. This returns JSON that looks like this:

{"routines":[{"routine_id":1,"name":"Morning Routine","start_time":"2020-03-09T14:24:38.000Z","end_time":"2020-03-09T15:24:44.000Z","is_approved":0}]}

I want to loop through the routines key and print out each routine as components in React. I don't really care about what type of component that gets used, I just want to get the data. I've tried a few methods:

Method 1: Using componentDidMount with fetch:

 constructor() {
    super();
    this.state = { routines: {} }
}

componentDidMount() {
    fetch('http://localhost:3000/routines')
    .then((response) => response.json())
    .then((responseJson) => {
        return responseJson;
    })
    .then( routines  => {
        this.setState({routines: routines});

    })
    .catch( error => {
        console.error(error);
    });
}


render() {
    console.log(this.state)

render of this.state logs an empty object, despite the then(routines portion of the code returning the correct data.

Method 2: Putting everything in componentDidMount

  async componentDidMount() {
    const response = await fetch("http://localhost:3000/routines")
    const json = await response.json()
    console.log('json');
    console.log(json);
    const routines = json.routines
    this.setState({routines})
}

Again, logging the state in render produces nothing while logging the json that gets returned from componentDidMount does return valid data.

Inside the render method i've also tried:

const { routines } = this.state;

And routines comes up as undefined.

Method 3: Directly calling a function to set the state.

constructor() {
        super();
        this.state = { routines: this.fetchData() }
    }

This ends up returning some weird data:

{"routines": {"_40": 0, "_55": null, "_65": 0, "_72": null}}

I'm assuming it's because react native does not want me to do this.

I just want a simple way to fetch data from an API and display that data in render. I've gone through about four tutorials and all of them end up with undefined or objects set as the default value in the constructor in the render method. Am I going crazy? It feels like this is somehow impossible..?

4
  • this.setState({routines}, () => console.log(this.state)); what does it show? Commented Mar 10, 2020 at 6:33
  • can you put your code in codepen or jsfiddle? Commented Mar 10, 2020 at 7:11
  • its because you are trying to use routines before its loaded by fetch call Commented Mar 10, 2020 at 7:12
  • @JatinParmar what would you use to fetch data then? Commented Mar 13, 2020 at 5:47

3 Answers 3

2

You do everything right, just use state in render and you will see updates.

constructor() {
    super();
    this.state = { routines: [] }
}

render() {
    const { routines } = this.state

    return (
        <View>
            {routines.map(item => <Text>{item.name}</Text>)}
        </View>
    )
}
Sign up to request clarification or add additional context in comments.

2 Comments

This results in an undefined object, which crashes the code. Probably because routines hasn't loaded yet.
No crashes, routines should be an array. Check routines before setState this.setState({ routines: routines || [] });
0

Since fetch is an async task the data this.setState({routines}) get's set after render() is executed. You can execute this.forceUpdate() after setting this.setState({routines}). This will re-execute render() when the data is set.

See: https://reactjs.org/docs/react-component.html#forceupdate

However, debugging mode can also be the culprit.

Comments

0

its may be because fetch call is async ,and your render method may try to use it before its loaded by the api call, so your componentDidMount should be like

 componentDidMount() {
 this.setState({routines:null})
//fire an api call
fetch('http://localhost:3000/routines')
.then((response) => response.json())
.then((responseJson) => {

    return responseJson;
})
.then( routines  => {
    this.setState({routines: routines});

})
.catch( error => {
    console.error(error);
});

}

now inside your render function you should first confirm that routines is not null and have some valid values like

render(){
 if(this.state.routines !==null){
   //your code to render component
 }else{
   //your loading or error message
  }
}

4 Comments

What's strange is when I render routines through mapping, I still get undefined objects, because this.state.routines has a default array value.
can you provide some fiddle, i would like to help you
After trying this again, render is only called once. It doesn't appear to re-try after the state is set and logged. Not sure how to provide a fiddle with a database :(
in feedle no need to have data base just replace api call with static api call

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.