0

Attempting to update state after data load on useEffect. Able to update a local variable but not state. I am following an example from https://www.robinwieruch.de/react-hooks-fetch-data/ where Robin sets state in a similar way. For some reason, the state variable is never set correctly in my case.

Using AWS Amplify to load graphQL data. Seems to work successfully for local variable but not state variable.

const [serviceTypes, setServiceTypes] = useState([{}]);
let myServiceTypes = [{}]; // try it with a local variable to debug

useEffect(() => {
  let unmounted = false;

  async function fetchData() {
    const result = await API.graphql(
      graphqlOperation(queries.listServiceTypes)
    );
    console.log(result);
    console.log('setting service types...');
    console.log(result.data.listServiceTypes.items);
    setServiceTypes(result.data.listServiceTypes.items);
    myServiceTypes = result.data.listServiceTypes.items;
    console.log(myServiceTypes); // set correctly
   console.log(serviceTypes); // empty
  }
  if (!unmounted) {
    fetchData();
  }
  return () => {
    unmounted = true;
  };
}, []); 

Expecting serviceTypes to be set to the data loaded. Instead it is empty.

skyboyer
  • 22,209
  • 7
  • 57
  • 64
GregHouse
  • 295
  • 1
  • 2
  • 15

2 Answers2

1

setState does not work synchronously like that. You cannot expect your serviceTypes variable to immediately contain the data right after you set it. It will be updated when the component re-renders. try moving the console.log(serviceTypes); outside of the useEffect.

see https://stackoverflow.com/a/36087156/5273790 for an explanation of setState async.

tgreen
  • 1,720
  • 1
  • 16
  • 28
  • I've modified my code to place in a hook very similar to https://medium.com/@cwlsn/how-to-fetch-data-with-react-hooks-in-a-minute-e0f9a15a44d6. Only change is it is an AWS Amplify GraphQL fetch not a url. I receive the error "Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function." What is confusing to me is that there are many similar code examples and yet which I implement them, they receive this error. – GregHouse Jul 03 '19 at 17:23
  • Seems to be working correctly now without warnings. This article was quite helpful. https://itnext.io/how-to-create-react-custom-hooks-for-data-fetching-with-useeffect-74c5dc47000a. Adding the mounted and AbortController() processing seems to have worked. – GregHouse Jul 03 '19 at 20:42
0

It's because you aren't thinking about the effect and renders correctly.

Mounting/Render 1

  • fetchData is called
  • setServiceTypes and passes the service type to the next render
  • serviceTypes is empty

Render 2

  • useEffect is not called
  • serviceTypes is now what the previous serviceTypes was set to

Try logging out the serviceTypes right before the render/return

Jake Luby
  • 1,718
  • 5
  • 16
  • Thanks. What I am trying to accomplish should be pretty simple. Load data via useEffect and set state which is bound to a Menu component. I have followed a couple of published articles which seem to do something similar. I seem to be missing something... this should not be that hard to accomplish. – GregHouse Jul 03 '19 at 16:47
  • You should edit the question and add the entire function you're trying to render. Your code should is definitely setting the state correctly in the effect since `console.log(myServiceTypes);` is returning correctly. There's an issue somewhere else – Jake Luby Jul 08 '19 at 16:25