0

I am working on a React Native project and I have a function that makes a GraphQL query:

 getPosts = async () => {
    const result = await API.graphql(graphqlOperation(listPosts))
    if(this.state.isMounted){
      this.setState({ posts: result.data.Posts.items,
        isLoading: false, isMounted: false})
    }
  }

This function is called in the componentDidMount function. I also have a isMounted field in the state that is initialized to false. At the very top of the componentDidMount function I have:

this.setState({ isMounted: true })

Regardless, I am still getting a warning about trying to set the state on an component that is unmounted. I should also mention that this Component is called from this.props.navigation.navigatecall.

ecain
  • 1,282
  • 5
  • 23
  • 54
  • use a plain property `this._isMounted` instead of `this.state.isMounted` – Dmitriy Mozgovoy Jan 09 '21 at 23:38
  • I get a warning that `this.isMounted` is deprecated and that I should just clean up subscriptions and pending requests in `componentWillUnmount`. I believe I'm doing that though. – ecain Jan 09 '21 at 23:57
  • 1) I'm talking about your own property called this._isMounted (or some another name you want) and not deprecated React property this.isMounted. The _isMounted property should NOT be a state property. 2) No. You're not doing that how they asking, you're just trying to make your own version of the deprecated isMounted API. You don't cancel any subscription there at all, you just try to ignore the results of those. – Dmitriy Mozgovoy Jan 10 '21 at 22:47
  • I have `.unsubscribe()` in my `componentWillUnmount` for my subscriptions. Isn't that how you're supposed to clean them up? I made a `_isMounted` prop NOT in the state, but that doesn't seem to fix the warning. – ecain Jan 10 '21 at 22:51
  • Yes, you should cancel all subscriptions, stop requests, clear timers, etc. And not try to change state after unmounting, but you are probably missing something. Since we don't have any code to see how you do this, it's hard to guess what exactly is wrong. – Dmitriy Mozgovoy Jan 10 '21 at 23:07
  • I want to clarify. Which API does mentioned `.unsubscribe ()` belong to? :) Don't take it literally - for example, for API.graphql () you have to use its cancellation API call - API.cancel (promise) to stop the request when your component unmounting. Each pending asynchronous function / promise resource must be stopped / disposed by using the cancellation API provided in each case. – Dmitriy Mozgovoy Jan 10 '21 at 23:18
  • Ah ok yes, the `.unsubscribe` is from the API api. So for example, in my `getPosts` method up above, would I call `this.getPosts.cancel()` ? – ecain Jan 10 '21 at 23:22

1 Answers1

0

Why you need the isMounted state? If you are using this state just to be a condition to set the state posts, you could just call the getPosts method inside the componentDidMount function and should work as you expected:

async componentDidMount(){
  await getPosts()
} 

You got it? Waiting for your feedback about my answer. Thx :)

  • I am calling the getPosts inside the componentDidMount. Maybe it’s an issue with something else then... – ecain Jan 09 '21 at 23:10
  • But I want you to remove this ``ìsMounted```state, you got it? So your ```getPosts``` would be like this: ```getPosts = async () => { const result = await API.graphql(graphqlOperation(listPosts)) this.setState({ posts: result.data.Posts.items, isLoading: false}) }``` Try like this and should work. – Gabriel Menezes da Silva Jan 09 '21 at 23:13
  • yes that’s how it was originally, but I had the same result. I just added the isMounted stuff because is saw it in another Stack Overflow post – ecain Jan 09 '21 at 23:14
  • Oh now I know what should be the problem, write the componentDidMount like this: ```async componentDidMount(){ await this.getPosts() }``` – Gabriel Menezes da Silva Jan 09 '21 at 23:16
  • So that does seem to make the problem go away. Why is it that using the `await` in front of the call works, but not if I change the code to do this: – ecain Jan 10 '21 at 00:06
  • `getPosts = async () => { await API.graphql(graphqlOperation(listSoundwaves)) .then( result => { this.setState({ posts: result.data.listSoundwaves.items, isLoading: false, isMounted: false}) }) }` – ecain Jan 10 '21 at 00:06
  • Isn't that essentially the same – ecain Jan 10 '21 at 00:06
  • 1
    @ecain using `await` and `then` is mixing different conventions ... you don't need `isMounted` at all ... error usually means data arrived [too late] but component was removed – xadm Jan 10 '21 at 16:35
  • but since there is an `await` on the actual graphQL call, how could it arrive "too late" ? – ecain Jan 10 '21 at 18:44
  • proper question would be why component disappears before its state can be updated – xadm Jan 10 '21 at 18:48
  • @xadm ah ok who controls when a component goes out of scope? – ecain Jan 10 '21 at 19:47
  • @ecain IDK, it's your project/you know the structure/conditions/whatever – xadm Jan 10 '21 at 19:49
  • I think that your code is not working because you're mixing the ``àwait``` keyword with the ```.then``` that is a ```promise```syntax, you got it? The use of ``àsync/await``` is a optimization of ``` promises. https://stackoverflow.com/questions/54495711/async-await-vs-then-which-is-the-best-for-performance -> This post is interesting to read about this subject. Waiting for your feedback, Thx :). @ecain – Gabriel Menezes da Silva Jan 10 '21 at 20:17