-
-
Notifications
You must be signed in to change notification settings - Fork 10.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
useRouterMatch returns new object on each render #7059
Comments
I think that makes sense. Can you submit a PR? |
Hi! There was kind of similar question about new The issue was closed because it is intentional, but now, with the @timdorr, is there any difference in these cases? Perhaps, P.S. It could really help people like me, which migrating from RR3 to the last one and still use redux and react-redux. After migration we found out that our 'connected pure components' from react-redux |
Yes, that was when using lifecycle methods and a class component. You could "memoize" by way of shouldComponentUpdate to prevent a render. With Hooks, you're already in a render cycle, so it's not possible to bail out. That's why useMemo/useCallback even exist, so you can safely memoize values directly. |
Thanks for quick reply! As i understood, you don't think that it makes sense if |
I face the same problem with |
same issue with useLocation
Got infinite loop. To detect location change with useEffect, I use as a workaround or solution :
Is it the right way ? |
I tried to reproduce infinite loop in my code for But my Location object didn't contain hash or search maybe your problem come from here but obviously if your looking for pathname changes you should definitevely put only this part in dependencies. No need to look for other changes if your not using them. |
Yes i can reproduce the infinite loop which is normal btw. You try to add a state with In my opinion the best practice with hooks dependencies is to be as accurate as possible on which variable you want to listen to. That avoid unnecessary operation and bugs that come from an object getting updated but not the part you want to look after. I think you also forget to add |
Still looking for an update. Can this be memoized inside the package? Scenario: Can't memoize the useRouteMatch() hook inside useMemo's callback either. What's the solution? Edit: |
A bit off topic, but simply using The location value isn't changed so it is trival to work-around, but quite a gothca IMO. facebook/react#15156 (comment) for a related discussion. |
If you want to perform side-effects on location change, then I think you can prob just rely on const location = useLocation();
const match = useMatch();
useEffect(() => {
// The location has changed
nonIdempotentSideEffect(match.params.foo);
}, [location]) Or I think you could make match stable in user land like this: const useStableRouteMatch = () => {
const _match = useRouteMatch();
const location = useLocation();
const [match, setMatch] = useState(_match);
useEffect(() => {
setMatch(_match);
}, [location]);
return match;
};
// ...
const match = useStableRouteMatch();
useEffect(() => {
// The location has changed
nonIdempotentSideEffect(match.params.foo);
}, [match]); However, I don't think using const useMemoRouteMatch = () => {
const match = useRouteMatch();
const location = useLocation();
return useMemo(() => match, [location]);
}
// ...
const match = useMemoRouteMatch();
useEffect(() => {
// The location has changed *or react has discarded the memo'd match value*
nonIdempotentSideEffect(match.params.foo);
}, [match]); |
Same for other hooks like Maybe passing props you want to subscribe to into this hooks may help. |
Nested routes trigger the infinite re-render loop. Would be great to memoize the hooks +1 |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. |
+1 |
I am still having this issue, is there a update on it? |
Unclear on what's the stance on (Haven't checked if v6 changed the behavior already.) |
In the meantime this |
An example of how I use function useListenHistory(fn) {
const [state, setState] = useState(fn());
const history = useHistory();
useEffect(() => history.listen(() => {
const newState = fn();
if (newState !== state) {
setState(newState);
}
}));
return state;
}
export function useAtHome() {
const getAtHome = () => window.location.pathname === '/';
return useListenHistory(getAtHome);
} |
This is causing all kinds of unnecessary re-rendering, we've had to write our own set of wrapper functions to compensate |
your example has zero memoization itself neither in |
I've opened up a PR to start a discussion on how this issue could be resolved in #7822. |
Is there any update on the PR? I can see all the check have passed, but there looks like no activity after April |
The update is that I'll be reviewing in the next week or two. This one is on the radar. |
fwiw I think this might have been a bit of an XY problem for me. I was blaming this library for rerendering too much (which might still be an issue that should be resolved), but I think that might have been such a big issue for me because when a certain component was rerendering for me, I had coded it poorly, and the component was throwing out a bunch of cache data (specifically i think i was throwing out an already initialized apolloClient). The real solution for me was probably just to stop reinitializing too many things on every render, instead of rerendering less. |
I think this issue can be closed as the |
It's just renamed to react-router/packages/react-router/index.tsx Line 409 in 3485453
|
Created a new PR (#8431) to resolve this issue. |
That's now released in 6.1.0! :) |
Version
5.1.2
Test Case
https://codesandbox.io/s/eloquent-wave-vlixh
Steps to reproduce
CodeSanbox has a reproducible case
Expected Behavior
useRouteMatch
hook returns a match object, when combined with auseEffect
it is expected that the effect will run only when the window location or path parameters changeActual Behavior
useRouteMatch
hook returns a match object, when combined with auseEffect
with the match as dependency the effect is triggered on every state change.The codesandbox example performs a state update on a timeout and logs
match
whenever it is changed. The logs show that on every update match has changed even if the path has not. Memoizing thematch
object onwindow.location.pathname
prevents this and has the expected behaviourThis line in the hook returns the result of
matchPath
which creates a new object every time it is executed.Possible solution would be to do something like
The text was updated successfully, but these errors were encountered: