Ad

How Can I Use The UseQuery Hook To Populate State In Other Hooks?

- 1 answer

I have been dealing with a few hook-related issues recently as I have been implementing hooks into a project of mine. I keep getting the error "Rendered more hooks than during the previous render."

It seems that the only way I can get my code to work is by putting the useQuery hook after all of the other hooks. This is a problem however as I want to populate some values of state with values from data on the query.

// code that doesn't error, but am not able to initialize state with query values

const [url, setUrl] = useState('')

const updateLink = useMutation(LINK_UPDATE_MUTATION, {
  variables: {
    id: props.id,
    url
  }
})

const { data, loading, error } = useQuery(LINK_QUERY, {
  variables: {
    id: props.id
  }
})

if (loading) {
  return <div>Loading...</div>
}
if (error) {
  return <div>Error! {error.message}</div>
}

vs

// code that errors with 'Rendered more hooks than during the previous render.'

const { data, loading, error } = useQuery(LINK_QUERY, {
    variables: {
      id: props.id
    }
  })

  if (loading) {
    return <div>Loading...</div>
  }
  if (error) {
    return <div>Error! {error.message}</div>
  }

const updateLink = useMutation(LINK_UPDATE_MUTATION, {
    variables: {
      id: props.id,
      url
    }
  })

const [url, setUrl] = useState(data.link.url)

I would expect that the useQuery hook could be used in a way to initialize other values with its query data.

If this isn't enough code or more explanation is needed just let me know. Thanks.

Ad

Answer

What you need to do is to update the state when the first hook results in a response. To do that you can make use of useEffect hook. You need to render all hooks at the top of your functional component.

const [url, setUrl] = useState('')

const updateLink = useMutation(LINK_UPDATE_MUTATION, {
  variables: {
    id: props.id,
    url
  }
})

const { data, loading, error } = useQuery(LINK_QUERY, {
  variables: {
    id: props.id
  }
})

useEffect(() => {
  if(data && data.link) {
    setUrl(data.link.url);
  }
}, [data])

if (loading) {
  return <div>Loading...</div>
}
if (error) {
  return <div>Error! {error.message}</div>
}
Ad
source: stackoverflow.com
Ad