I use a Tree from mui v5 and I want to add in searchParams node that are selected and expanded. To do this I use the hook useSearchParams from React Router (v6).
The fact is that event selected and expanded are firing in the same rendering of the component.
So when the first write params by setSearchParams(...) the second do the same but with the same searchParams and erase params setted by the first.
I made a CodeSandBox which reproduces the behavior.
I try to use a ref to allow to mutate freshSearchParamsbut I did not succeed.
The problem is that the TreeView component is dispatching both onNodeSelect and onNodeToggle on the same Click. One thing you can do is customize both handleToggle and handleSelect functions, so they combine the two expanded and selected variables.
I'd take another approach to this scenario. I'd use a custom hook that handles the Tree state and wraps that state with that searchParams functionality. You can initialize the state from the URL and update the search parameters when the state is updated. I'd implement that URL update with a useEffect that compares status to URL and makes the appropriate updates.
Here's a possible implementation of that custom hook.
const useTreeUrlStatus = () => {
const [searchParams, setSearchParams] = useSearchParams();
const [state, setState] = useState(() => {
return {
selected: searchParams.get("selected") ?? "",
expanded: searchParams.get("expanded")
? searchParams.get("expanded").split(",")
: []
};
});
useEffect(() => {
if (
searchParams.get("selected") !== state.selected ||
searchParams.get("expanded") !== state.expanded
) {
setSearchParams({
selected: state.selected,
expanded: state.expanded.join(",")
});
}
}, [state, searchParams, setSearchParams]);
const updateState = (key, value) => {
setState((prevState) => {
const newState = { ...prevState, [key]: value };
return newState;
});
};
return [state, updateState];
};
You have a working sandbox here forked from your posted sandbox.