Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

No longer recreating histories within MemoryRouter #151

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

PatrickShaw
Copy link
Contributor

Similar to #150 I don't think we want to create a new memory history on every render of MemoryRouter. Memory history is supposed to maintain state outside the lifetime of a single render.

I've fixed this issue by putting useRef around the createMemoryHistory to retain the same instance.

@PatrickShaw PatrickShaw force-pushed the avoid-create-memory-history-in-memory-router branch 3 times, most recently from e026d73 to 7151009 Compare May 4, 2022 04:55
@PatrickShaw PatrickShaw force-pushed the avoid-create-memory-history-in-memory-router branch from 7151009 to 4a2f26d Compare May 4, 2022 05:01
return (
// @ts-ignore suppress history will be overwritten warning
<Router history={history} {...(routerProps as RouterProps)}>
<Router history={historyState.current.getHistory()} {...other}>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getHistory will retrieve the same history instance so longer as location doesn't change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as RouterProps was removed as it makes tsc complain that the history prop is always overridden (since RouterProps always defined history). I'm surprised this wasn't previously causing TS compilation to fail.

Possibly my node_modules versions differ from what this code was originally tested on. Still, I think it's an improvement.

};

if (resourceData) {
routerProps = { ...routerProps, resourceData };
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what the intention was here. Router allows resourceData and resourceContext to be defined so I've removed these if conditions in the equivalent destructure.

basePath={basePath}
routes={routes}
resourceData={resourceData}
resourceContext={resourceContext}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Normally I'd just spread the props from MemoryRouter onto Router but it looks like the code intentionally picked out specific props using getRouterProps so I've retained equivalent logic in this PR.

const newGetHistory = () =>
createMemoryHistory({
initialEntries: location !== undefined ? [location] : undefined,
});
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't want execute createMemoryHistory in the render function if it's not going to be used. Hence we store a reference to a callback rather than the history instance itself.

createMemoryHistory({
initialEntries: location !== undefined ? [location] : undefined,
})
);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't want to create an unnecessary history object on every render if we're not going to use it, so I've stored the history in a memoized callback instead (with the assumption that an uncalled callback is probably going to be cheaper than creating the history API).

if (resourceData) {
routerProps = { ...routerProps, resourceData };
}
const lazy = <T extends any>(callback: () => T) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could use https://lodash.com/docs/4.17.15#memoize here. I see lodash being used elsewhere in this code base but it seemed a bit excessive since we don't need to do any argument caching.

if (resourceData) {
routerProps = { ...routerProps, resourceData };
}
const useMemoryHistory = (location: string | undefined) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stored all the ugliness of trying to retain the same instance across renders in this hook.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant