1

I have a table that has the data of a different fetch per row. Each row will also be able to trigger a fetch independently of the other rows. If each row is a component that has a button to refetch, the implementation is easy. I just put call useQuery per row (a component).

The problem is filtering and sorting, because the fetched data is only on the rows so there is no global list containing all the information.

I tried to implement it with useQueries or just use components. But I only come up with gnarly solutions. One of those would be to have row components that call useQuery and also set a value (useState) on a parent. This looks like I'm setting the same data at 2 levels and if I get a big table that virtualizes rows, the useQuery inside the components are not triggered because the component is not created.

The problem is hard to describe, so if there is some part that needs clarification please let me know.

===

This is not the real code, just code to try to represent what I have:

function Row({cell}) {
  const [fetch, setFetch] = useState(null);
  const query = useQuery(["somekey", refetch], fetchFn(cell.url))

  const refetch = () =>setFetch(Date.now())

  return (<div onClick={refetch}>{query.data.value}</div)
}

function Table({array}) {
 return (<div>
          {array.map(el => <Row cell={el}/>})}
        </div>)
}
6
  • Can you share some of your code? Commented Apr 1, 2021 at 13:04
  • I'll try to put a slice of it, because it has too much stuff. And the data fetching is mixed with the React elements. That's one thing I was trying to avoid Commented Apr 1, 2021 at 13:10
  • so you basically want to filter and sort the array elements but the filter will apply on data that is returned on each row? Commented Apr 1, 2021 at 13:27
  • @marinvirdol as it is implemented now, yes. Commented Apr 1, 2021 at 13:28
  • it would be great if you could re-create a contrived example of what you are trying to do, right now it is a bit hard Commented Apr 1, 2021 at 13:40

1 Answer 1

1

This is generally not the easiest to implement with react-query, because it doesn't have a normalized cache, but here is how I would approach the problem:

  • have one list query: useQuery('myList')
  • each row has it's own query: useQuery('myList', id)
  • I would use initialData and staleTime to pre-populate the detail query with data from the list query and avoid unnecessary fetches when each row mounts.
  • when you refetch a single row, you:
    • refetch the one detail query, as you said, easy
    • onSuccess update the query data of the list with the new data from that detail query (with queryClient.setQueryData)

of course, all of this would be easier if you just had one list query and operate everything on that, but than you can't do individual refetches of one row - you'd always refetch the whole list. Usually, that's not too bad either. With the above approach, you get a bit into "syncing" state between the detail and the list query - also not so nice.

Sign up to request clarification or add additional context in comments.

2 Comments

What other alternative you think it would be easier? I think this is sort of what I was thinking of doing (still need to research the staleTime and setQueryData, don't know that part of the API). I'm thinking of sending some data to the parent and use it to sort/filter the table. That and turn off the virtualization. The sorting, filtering and virtualization are quite tricky.
if refetching a single item is not that important for you, I would just do one list query and refetch the whole list every time. for most lists, this doesn't matter. You can still create a useSelector like api to pick one entry from the list with the select option

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.