0

I'm very new to react and i'm confused why my state is not updated in another method of mine see example below.

fetchMovies = () => {
    const self = this;
    axios.get("https://api.themoviedb.org/3/trending/movie/day?api_key=XXXXXXX")
        .then(function(response){
            console.log(response.data)
            self.setState({
                collection: response.data.results
            })
            console.log(self.state.collection)
        });
}

makeRow = () => {
    console.log(this.state.collection.length);
    if(this.state.collection.length !== 0) {
        var movieRows = [];
        this.state.collection.forEach(function (i) {
            movieRows.push(<p>{i.id}</p>);
        });

        this.setState({
            movieRow: movieRows
        })
    }

}

componentDidMount() {
    this.fetchMovies();
    this.makeRow();
}

When inside of fetchMovies function i can access collection and it has all the data but this is the part i can't understand in the makeRow function when i console log the state i would of expected the updated state to show here but it doesn't i'm even executing the functions in sequence.

Thanks in advance.

Jake
  • 21
  • 3
  • https://reactjs.org/docs/faq-state.html – Brian Thompson May 28 '20 at 13:57
  • Does this answer your question? [Why calling react setState method doesn't mutate the state immediately?](https://stackoverflow.com/questions/30782948/why-calling-react-setstate-method-doesnt-mutate-the-state-immediately) – Brian Thompson May 28 '20 at 13:57
  • A little explanation: it has nothing to do with it being in a different method. Even if you console logged in the same method you would not see the updated values. That's just how it works. The class component way to use updated values would be to use the optional callback in `setState` or use a lifecycle method like [`componentDidUpdate`](https://reactjs.org/docs/react-component.html#componentdidupdate). – Brian Thompson May 28 '20 at 13:59
  • In order for react methods to have access to this.state and this.props we need to bind the React component ‘this’ context to those methods. See: https://medium.com/byte-sized-react/what-is-this-in-react-25c62c31480 – Rahul Pillai May 28 '20 at 14:02
  • @RahulPillai That's not true. The OP is using arrow functions which operate differently. [From the docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions): *An arrow function does not have its own `this`. The `this` value of the enclosing lexical scope is used; arrow functions follow the normal variable lookup rules*. – Brian Thompson May 28 '20 at 14:09
  • @BrianThompson but the calling function is the componentDidMount() which is not arrow function right? Sorry I might be wrong cuz I am so used to using hooks – Rahul Pillai May 28 '20 at 14:22
  • Check out [this answer](https://stackoverflow.com/questions/49501775/are-reacts-lifecycle-method-autobound-if-not-should-we-be-binding-them-with-b) for more explanation. But in short, you do not need to bind lifecycle methods, they will always have access to `this` in the correct context. Traditional functions get `this` by the context from which they are called, arrow functions do not, so even if the calling method did not have the correct `this`, it would not effect the arrow function. – Brian Thompson May 28 '20 at 14:24
  • It appears that you have posted sensitive/private information. Please reset your passwords and/or revoke API keys and tokens, as they are considered compromised when posted on the internet. If personally-identifiable information was posted, please [edit] out the info then flag your post for a moderator to redact the revisions. – Samuel Liew May 29 '20 at 01:47

2 Answers2

1

The setState() documentation contains the following paragraph:

Think of setState() as a request rather than an immediate command to update the component. For better perceived performance, React may delay it, and then update several components in a single pass. React does not guarantee that the state changes are applied immediately.

To access the modified state you need to use the function signature setState(updater, [callback]), so in your case it should be;

self.setState({
    collection: response.data.results
}, () => { // Will be executed after state update
  console.log(self.state.collection) 
  // Call your make row function here and remove it from componentDidMount if that is all it does.
  self.makeRow()
} )
3limin4t0r
  • 19,353
  • 2
  • 31
  • 52
paldron
  • 26
  • 2
1
  1. the collection is set after the async call is resolved. Even though makeRow method is called after fetchMoview, coz of async call, u will never know when the call will be resolved and collection state will be set.

  2. There is no need to keep movieRows in the state as that is just needed for rendering. Keeping html mockup in the state is never a good idea.

So u should just call fetchMoviews in the componentDidMount and render the data in as follows:

render() {
 const { collection } = this.state;

 return (
  <>
   {
     collection.map(c => <p>{c.id}</p>)
   }
  </>
 )
}

make sure the initial value for collection in the state is [] .

Vishal Sharma
  • 316
  • 1
  • 8