Mael Landrin
Mael Landrin

Reputation: 123

React Setstate makes my state item undefined after JSONizing it

I'm trying to make a workout log for myself and as a training for React and Node.js. I've got my own API with many functions, including one called "/get-workouts", which is, as the name says, to get workouts from the database.

Here's the API

app.get('/get-workouts', (req, res) => {
db('workoutlogger').select('*')
.limit(3)
.from('workouts')
.then(workouts => {
    if(workouts.length) {
        console.log(workouts);
        res.status(200).json(workouts);
    } else {
        res.status(400).send('No workouts found');
    }
})
.catch(err => {
    console.log(err);
    res.status(404).send('Error getting workouts')
   })
})

Here's my frontend :

constructor(props) {
    super(props)
    this.state = {
        workoutList: {}
    }
}

getWorkouts = () => {
    fetch('http://localhost:3001/get-workouts')
    .then(workouts => {
        workouts.json();
    })
    .then(workoutList => {
        this.setState({workoutList})
    })
    .catch(err => console.log('There was an error getting workouts', err))
}

componentDidMount() {
    this.getWorkouts();
}

If I console.log "workouts" in the first .then() of my fetch. My API clearly logs the list of the last 3 workouts I logged in, and initially, this.state.workoutList is an object. But once set.state supposedly set the workoutList to be a list of my workouts, it logs as undefined, and I can't display it. Where does the problem come from ?

Upvotes: 0

Views: 70

Answers (2)

Neeraj Kumar
Neeraj Kumar

Reputation: 226

Arrow function needs to be understood correctly here.

Arrow function without curly braces implicitly returns whatever the next statement evaluates to. However, if you use curly braces, you are forming a block which is nothing but a list of statements (which evaluate to undefined). Thus we need to use return explicitly in that case.

constructor(props) {
    super(props)
    this.state = {
        workoutList: {}
    }
}

getWorkouts = () => {
    fetch('http://localhost:3001/get-workouts')
    .then(workouts => {
        return workouts.json();
    })
    // above then fn can also be written (without curly braces) as below:
    // .then(workouts => workouts.json()) -- removing curly braces returns result of statement implicitly
    .then(workoutList => {
        this.setState({workoutList})
    })
    .catch(err => console.log('There was an error getting workouts', err))
}

componentDidMount() {
    this.getWorkouts();
}

Upvotes: 1

Jayce444
Jayce444

Reputation: 9063

You need to pass values between consecutive .thens, they aren't implicitly passed. The return value of one .then becomes the argument of the next. So do this:

.then(workouts => workouts.json())
.then(workoutList => {
    this.setState({workoutList})
})

Removing the curly braces means it implicity returns workouts.json(), which will then becomes the workoutList argument in the next .then

Upvotes: 3

Related Questions