next-redux-wrapper
next-redux-wrapper copied to clipboard
next-redux-wrapper usage slows down route change
Describe the bug
Whenever I use next-redux-wrapper, changing routes starts to get really slow.
export const getServerSideProps: GetServerSideProps<I18nProps<MyLocale>> = getStore((store) => async (ctx) => {
// ...
store.dispatch(setFeatureFlags(flags));
// ...
store.dispatch(updateDevice(getSelectorsByUserAgent(ctx.req.headers["user-agent"])));
return ...;
});
With the code above, whenever I change routes, it takes around 10s to change on dev and 5s on prod. If I remove it, it becomes instant, like milliseconds.
To Reproduce
The code is proprietary, I can't fork or clone it.
Steps to reproduce the behavior:
Just use this library with some dependencies like usedapp, or theming, or any UI lib. Check how long it takes to change routes. Remove it, and you'll see the difference.
Expected behavior
Using redux shouldn't impact the app routing load time.
Screenshots
If applicable, add screenshots to help explain your problem.
Desktop (please complete the following information):
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 6]
Additional context
hi , i had this problem too, you can use 8.0.0-rc.1 instead of 7.0.5 there is some changes
for create store you must use configureStore
const makeStore = () =>
configureStore({
reducer: appReducer,
devTools: true,
});
export const wrapper = createWrapper(makeStore, {debug: false});
and in _app.js:
const App = ({Component, ...rest}) => {
const {store, props} = wrapper.useWrappedStore(rest);
return (
<Provider store={store}>
<Component {...props.pageProps} />
</Provider>
)
}
That RC is pretty good. Thank you @roshaninet
When can we expect the RC to be ready? Do you need help with testing/docs
RC looks pretty OK, I have not received any bug reports for quite a while, so I might promote it. Stay tuned, I will release a new major version shortly.
P.S. The only thing that might require extra effort is new app
dir with slightly alternative fetching mechanism, which includes React Server Components. I am still figuring out how to add support for it.
Updating to 8.0.0-rc.1 did help me get rid of this issue, but now HYDRATE is only called on initial page load, but not during regular page navigation. any ideas?
I noticed this useEffect (https://github.com/kirill-konshin/next-redux-wrapper/blob/master/packages/wrapper/src/index.tsx#L178) is never being called, event though initialStateFromGSPorGSSR
is clearly a different value. So hydrate is never being called in my case. I'm clueless why this is happening.
I've encountered this issue as well, and in my case it's because, on client-side navigation with next/link
and next/router
, identical HYDRATE
actions are repeatedly dispatched - 700ish times per navigation for me in dev mode. I think it puts the app into a spinlock until some async task finishes - something, somewhere (possibly not in next-redux-wrapper
) is not waiting when it should. I have not found the root cause.
Using React 18.2, Next 12.1.6, next-redux-wrapper
7.0.5. Other possibly relevant libraries are RTK Query with @reduxjs/toolkit
1.8.2 and connected-next-router
4.1.1 - calling them out because they both do interesting things on route change.
Here's what I found out and a workaround that seems to work for my case, in case they're useful to you @kirill-konshin or anyone else having this problem. I am using App-level getInitialProps
only.
It's coming from withRedux.shouldComponentUpdate
: nextProps.initialState
and this.props.initialState
are different repeatedly, so this.hydrate
is called repeatedly.
I think what's supposed to happen is: HYDRATE
is dispatched, the store is updated, this.props
has the updated store, that makes this.props === nextProps
, and we move on. But something happens in that process and React tries to re-render before the store is updated, so WrappedApp's props aren't updated yet, so it dispatches HYDRATE
again. Repeat until... this is where I got stuck.
I overrode WrappedApp.prototype.shouldComponentUpdate
with an identical body, with the this.hydrate
call in a timeout. 0 timeout was the same, but waiting 10-50ms reduced the number of dispatches and waiting 100-150ms eliminated the duplicate dispatches. (This is why I wonder if RTK Query is involved - 50-100ms is on the network request timeframe.)
In my use case (but not necessarily others!), changing route always changes the Next page. So if we've already dispatched a HYDRATE
for this.props.Component
, we know the store is updated. So my workaround is to remember the last page component we hydrated for, and only hydrate if it's different from this page component:
const WrappedApp = wrapper.withRedux(App);
let lastComponent;
WrappedApp.prototype.shouldComponentUpdate = function(nextProps, nextState, nextContext) {
if (nextProps?.pageProps?.initialState !== this.props?.pageProps?.initialState
|| nextProps?.initialState !== this.props?.initialState) {
if (lastComponent !== this.props.Component) {
this.hydrate(nextProps, nextContext);
lastComponent = this.props.Component;
}
}
return true;
};
My app doesn't use page-level getInitialProps
or getServerSideProps
, it doesn't look like this would break those but I haven't tested that case. It might break if you render the same page on different routes though!
any update on releasing version 8?
I can release it, it's been in beta for quite some time.
Hi, I am getting warning when upgrading to 8.0.0-rc.1 from 7.0.5, my implementation is same as the readme guide /!\ You are using legacy implementaion. Please update your code: use createWrapper() and wrapper.useWrappedStore().
https://github.com/kirill-konshin/next-redux-wrapper/tree/8.0.0-rc.1#app
Here is how you can use the new API https://github.com/kirill-konshin/next-redux-wrapper/blob/8.0.0-rc.1/packages/demo-redux-toolkit/pages/_app.tsx
I can release it, it's been in beta for quite some time.
Hi! Any update on this? We would love an official 8.0.0 release. Thanks for all your work on this!
TypeError: redux_store__WEBPACK_IMPORTED_MODULE_5_.wrapper.useWrappedStore is not a function
//MyApp.js
function MyApp({ Component, ...rest }) {
const {store, props} = wrapper.useWrappedStore(rest);
return (
<>
<Provider store={store}>
<Navbar />
<Component {...props.pageProps} />
</Provider>
</>
);
}
export default MyApp
//reducer.js
const combinedReducer=combineReducer({
login: loginReducer,
participants: addParticipantReducer,
trainings: addTrainingsReducer,
})
const reducer = (state, action) => {
if (action.type === HYDRATE) {
const nextState = {
...state, // use previous state
...action.payload, // apply delta from hydration
};
return nextState;
} else {
return combinedReducer(state, action);
}
};
export const makeStore = () =>
configureStore({
reducer,
});
export const wrapper = createWrapper(makeStore, { debug: true });
I have upgraded from v7.0.5 to 8.0.0-rc.1 . v7.0.5 made routes really slow but now 8.0.0-rc.1 is throwing this error. What can I do this get this working @kirill-konshin @madmed88 ?
I use 8.0.0-rc.1 and all the navigation works perfectly except locale change:
<Link
href={router?.asPath ?? "/"}
locale={otherLocale}
passHref
>
As soon as I add locale, the page switch takes a long time and redux creates +-700 states/commits
TypeError: redux_store__WEBPACK_IMPORTED_MODULE_5_.wrapper.useWrappedStore is not a function
//MyApp.js function MyApp({ Component, ...rest }) { const {store, props} = wrapper.useWrappedStore(rest); return ( <> <Provider store={store}> <Navbar /> <Component {...props.pageProps} /> </Provider> </> ); } export default MyApp //reducer.js const combinedReducer=combineReducer({ login: loginReducer, participants: addParticipantReducer, trainings: addTrainingsReducer, }) const reducer = (state, action) => { if (action.type === HYDRATE) { const nextState = { ...state, // use previous state ...action.payload, // apply delta from hydration }; return nextState; } else { return combinedReducer(state, action); } }; export const makeStore = () => configureStore({ reducer, }); export const wrapper = createWrapper(makeStore, { debug: true });
I have upgraded from v7.0.5 to 8.0.0-rc.1 . v7.0.5 made routes really slow but now 8.0.0-rc.1 is throwing this error. What can I do this get this working @kirill-konshin @madmed88 ?
upgrade next-redux-wrapper to version 8
Not sure if it related but I'm finding state updates are generally very sluggish when using next-redux-wrapper this is when I use
const { store, props } = wrapper.useWrappedStore(rest);
Not sure if it related but I'm finding state updates are generally very sluggish when using next-redux-wrapper this is when I use
const { store, props } = wrapper.useWrappedStore(rest);
Can you provide measurements? I have not noticed any performance degradation. It could be due to your reducers. Wrapper has minimal overhead, just a few very small loops over simple objects.