How to sneak dynamic data into react state from apollo query without breaking react's rules

Viewed 59

My goal is to run the apollo query hook (useDataAboutThing), get the part of the data object I need, and get that resulting data into event with setEvent. Every attempt I try at solving this, I violate the law of hooks or create a feedback loop. This seems like it should be easy which probably means I have a flawed understanding of React that needs to be corrected.

type ComponentProps = {
  id: number;
}

const Component = ({ id }: ComponentProps) => {
  const { data, loading, error } = useDataAboutThing({
    variables: {
       id: id,
    },
  });

  const [event, setEvent] = React.useState([]);
  
  // without checking these, data is undefined
  if (loading) return <div>Loading...</div>;

  if (error) return <div>Error!</div>;

  const dataInformation = data.information;

  React.useEffect(() => {
    setEvent(dataInformation)
  }, []) // Error: Rendered more hooks than during the previous render.

  return (
    ...
  );
2 Answers

Your useEffect without dependency is executed when the function is called,

  1. you should make it dependent on data.
  2. Check if the expected data exists in data
  3. assign it to the state.
type ComponentProps = {
  id: number;
}

const Component = ({ id }: ComponentProps) => {
  const { data, loading, error } = useDataAboutThing({
    variables: {
       id: id,
    },
  });

  const [event, setEvent] = React.useState([]);

  if (loading) return <div>Loading...</div>;

  if (error) return <div>Error!</div>;

  React.useEffect(() => {
    if(data.information) setEvent(dataInformation)
  }, [data]) // Error: Rendered more hooks than during the previous render.

  return (
    ...
  );

Now first: useEffect cannot be called conditionally (after if condition) so before your check whether it's loading or having errors you have to locate the useEffect . second: since the logic in your useEffect happens based on the data you have to include it inside array's dependencies .

type ComponentProps = {
  id: number;
}

const Component = ({ id }: ComponentProps) => {
  const { data, loading, error } = useDataAboutThing({
    variables: {
       id: id,
    },
  });

  const [event, setEvent] = React.useState([]);

      React.useEffect(() => {
       if (data?.information) {
          setEvent(data.information)
       }
      }, [data]);

  if (loading) return <div>Loading...</div>;

  if (error) return <div>Error!</div>;

  return (
    ...
  );
Related