Atif Khan
Atif Khan

Reputation: 224

How to get the variables of id from another queried looped map's id

So I'm trying to get the userId from another queried looped map's id.

The error is: Error: Rendered more hooks than during the previous render.

The error started showing when I added this inside the map:

const { data: { getUser } = {} } = useQuery(FETCH_USER_QUERY, {
          variables: {
            userId: something?.id,
          },
        });

on my component... This is my full component code:

export default function SomethingComponent() {
  const { data: { getSomething } = {} } = useQuery(
    FETCH_SOMETHING_QUERY
  );

  return (
    <>
      {getSomething?.map((something) => {
        const { data: { getUser } = {} } = useQuery(FETCH_USER_QUERY, {
          variables: {
            userId: something?.id,
          },
        });
        return (
          <div>
            <h1>{getUser.name}</h1>
            {/* ... */}
            {/* ... */}
            {/* ... */}
            {/* ... */}
            {/* ... */}
            {/* ... */}
          </div>
        );
      })}
    </>
  );
}

And this is for the Query of Something:

const FETCH_SOMETHING_QUERY = gql`
  {
    getSomething {
      id
    }
  }
`;

And for the query of the user:

const FETCH_USER_QUERY = gql`
  query ($userId: ID!) {
    getUser(userId: $userId) {
        # ...
    }
  }
`;

Ive tried thinking on how to fix this myself but i dont know any other way to get the something.id without going inside the looped map. So i tried searching for the same error and they are about the hooks in the wrong order or place.

Upvotes: 1

Views: 67

Answers (1)

Kaung Myat Lwin
Kaung Myat Lwin

Reputation: 1109

What you did was breaking the rules of hooks.

You'll need to utilize useApolloClient hook in order to manually execute the queries.

However, since we need to get the users individually, we can approach two ways for this.

The first way is to get the initial data first, then put it in useEffect hook with client extracted from useLazyQuery and then set the state one by one (which I think is a bit complicated):

The code below is just an idea. I won't guarantee that it will work if you copy+paste it.

// your previous code here
const [users, setUsers] = useState([])
const {
  client
} = useApolloClient()

useEffect(() => {
  if (getSomething.length > 0) {
    getSomething.forEach(async({
      id: userId
    }) => {
      const {
        data: newUsers
      } = await client.query({
        query: FETCH_USER_QUERY,
        variables: {
          userId,
        },
      })
      setUsers([...users, ...newUsers])
    })
  }
}, [getSomething])

2nd approach is to breakdown the component into smaller one with a fetch logic inside it.

export default function SomethingComponent() {
  const { data: { getSomething } = {} } = useQuery(
    FETCH_SOMETHING_QUERY
  );

  return (
    <>
    {getSometing.map((user) => <UserComponent userId={user.id} />)}
    </>
  );
}

// UserComponent.js
export default function UserComponent({ userId }) {
  const { data: { user } = {} } = useQuery(
    FETCH_USER_QUERY, { variables: { userId } }
  );

  return (
    <>
    {user?.name}
    </>
  );
}

Upvotes: 1

Related Questions