frozen-sapphire
frozen-sapphire3w ago

lazy loading and useList

Hi everybody, so I'm trying to implement lazy loading for the Tree View component as described here: https://mui.com/x/react-tree-view/rich-tree-view/lazy-loading/ I'm using useList to fetch data from a graphql backend. The command normally works fine but if I invoke it as part of the lazy loading mechanism of this component it somehow doesn't work, and in the console I have this message: proxy.js:1 Uncaught Error: Attempting to use a disconnected port object at handleMessageFromPage (proxy.js:1:779) I'm using vite proxy for the backend api. Does it matter? The code for the fetch function is the following: const fetchData = async (id: string | undefined): TreeItemType[] => { console.debug("Fetching data for ", id); const {data, isLoading, isError} = useList<CiSeries, HttpError>({ resource: "CiFolder", meta: { gqlQuery: TREE_LIST, variables: { seriesName: props.seriesName, }, }, pagination: { mode: "off" }, queryOptions: { retry(failureCount, error) { return !!(error?.message.includes("Network Error") && failureCount <= 3); }, }, }); return data?.data.map(item => (dataMapper(item))) ?? []; };
Rich Tree View - Lazy loading - MUI X
Lazy load the data from your Tree View.
2 Replies
kapa.ai
kapa.ai3w ago
Hi @fmarino. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Your issue seems to be related to how you are using the useList hook inside your fetchData function. According to the Refine documentation, useList is a React hook and must be called at the top level of a React component or another custom hook—not inside an async function or a callback. React hooks cannot be conditionally or imperatively called, as this breaks the rules of hooks and will not work as expected. This is likely why your data fetching is not working when triggered by the lazy loading mechanism of the Tree View component. What’s wrong with your approach:
const fetchData = async (id: string | undefined): TreeItemType[] => {
// ...
const {data, isLoading, isError} = useList<CiSeries, HttpError>({ ... });
// ...
};
const fetchData = async (id: string | undefined): TreeItemType[] => {
// ...
const {data, isLoading, isError} = useList<CiSeries, HttpError>({ ... });
// ...
};
This is not a valid usage of useList. Instead, you should call useList at the top level of your component or inside a custom hook, and then use its results in your component logic or event handlers. How to implement lazy loading with useList: If you need to fetch data on demand (e.g., when a tree node is expanded), you should use a state variable to store the parameters (like the node ID), and then pass those parameters to useList. You can control when the query runs using the enabled option in queryOptions. Alternatively, for fully imperative fetching, you might consider using useCustom with enabled: false and then call refetch when needed, as suggested in a related GitHub issue for "lazy query" patterns in Refine. Here’s a simplified example based on that approach:
const [nodeId, setNodeId] = useState<string | undefined>(undefined);
const { data, refetch } = useList<CiSeries, HttpError>({
resource: "CiFolder",
meta: {
gqlQuery: TREE_LIST,
variables: {
seriesName: props.seriesName,
nodeId, // pass the current nodeId
},
},
pagination: { mode: "off" },
queryOptions: {
enabled: !!nodeId, // only fetch when nodeId is set
retry(failureCount, error) {
return !!(error?.message.includes("Network Error") && failureCount <= 3);
},
},
});

// When you want to fetch data for a node (e.g., on tree expand):
const handleNodeExpand = (id: string) => {
setNodeId(id);
refetch();
};
const [nodeId, setNodeId] = useState<string | undefined>(undefined);
const { data, refetch } = useList<CiSeries, HttpError>({
resource: "CiFolder",
meta: {
gqlQuery: TREE_LIST,
variables: {
seriesName: props.seriesName,
nodeId, // pass the current nodeId
},
},
pagination: { mode: "off" },
queryOptions: {
enabled: !!nodeId, // only fetch when nodeId is set
retry(failureCount, error) {
return !!(error?.message.includes("Network Error") && failureCount <= 3);
},
},
});

// When you want to fetch data for a node (e.g., on tree expand):
const handleNodeExpand = (id: string) => {
setNodeId(id);
refetch();
};
This way, you respect the rules of hooks and can trigger data fetching in response to user actions, which is the essence of lazy loading in this context. For more details, see the discussion and solution in this GitHub issue: FEAT Lazy Query Hooks. Regarding the Vite proxy error:
The error message about a "disconnected port object" is not directly related to Refine or useList, but may be a side effect of the incorrect hook usage or a problem with your development environment. Make sure your Vite proxy is correctly configured and that your backend is reachable. Summary:
- Do not call useList inside an async function or callback. - Use state and the enabled/refetch pattern for on-demand (lazy) data fetching. - See the linked GitHub issue for a working pattern with Refine and lazy queries. If you need a more detailed example or further clarification, let me know! ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3w ago
<@1178663081463791677> Kapa.ai is still learning and improving, please let me know how I did by reacting below.

Did you find this page helpful?