7

I'm struggling to understand how to best organise my code to set initial useState() in React, while using GraphQL and Apollo to bring in the data. This is my code. As you can see I want to see a part of the 'data' to set the initial state, but when I move setSTate below the loading and error lines, I get the following error:

React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render. Did you accidentally call a React Hook after an early return? react-hooks/rules-of-hooks

How should I be better organising this? Do I have to use Apollo's state management library because I would prefer to use React useState hooks instead.

const GET_LATEST_POSTS = gql`
query {
"graphql query is in here"
}

...

const Slider = () => {

const { data, loading, error } = useQuery(GET_LATEST_POSTS)

if (loading) return 'Loading...'
if (error) return `Error! ${error.message}`

const [ currentMovie, setMovie ] = useState(data)
}
unicorn_surprise
  • 951
  • 2
  • 21
  • 40
  • 1
    If you need to use the data to initialize state, then use `useEffect` as already pointed out in the answers. However, you should only create separate component state like this if and only if you intend on mutating the state later. For example, if you're using the data from Apollo to populate a form that a user will then edit. If this is *not* the case, then you don't need `useState` -- just use the `data` directly. – Daniel Rearden Mar 18 '20 at 09:24

2 Answers2

17

you can make use of useEffect in React, like this

const Slider = () => {

    const { data, loading, error } = useQuery(GET_LATEST_POSTS)
    const [ currentMovie, setMovie ] = useState(undefined);

    useEffect(() => {
        if(loading === false && data){
            setMovie(data);
        }
    }, [loading, data])

    if (loading) return 'Loading...'
    if (error) return `Error! ${error.message}`
    // you can check if the currentMovie is undefined and use it to return something
    if(currentMovie) return `Movie ... do something with the currentMovie`

    }
Hemanath
  • 1,075
  • 6
  • 15
  • For typescript I also found it necessary to return null without any if statement. My component didn't load without it. // while waiting for data return null; . If I don't have it I get this error: Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null. – Royer Adames Nov 30 '21 at 23:57
7

Did you accidentally call a React Hook after an early return?

Your error is explained in above line.

According to rules of hook you should not call useState after your component returns something.

const Slider = () => {

const { data, loading, error } = useQuery(GET_LATEST_POSTS)


const [ currentMovie, setMovie ] = useState()

 useEffect(() => {
    if(!loading && data){
        setMovie(data);
    }
  }, [loading, data])

if (loading) return 'Loading...'               //your component's return should always be after all hook calls//
if (error) return `Error! ${error.message}`
}
Atin Singh
  • 3,624
  • 2
  • 18
  • 25