Skip to content

Commit 8e098f7

Browse files
Use useMemo for hydration and avoid unnecessary hydrates (#510)
* Use useMemo for hydration and avoid unnecessary hydrates (#502) * Upgrade packages and refactor a bit * Added necessary testing dependency * Stop hydrating on server and use useLayoutEffect for client hydration * Added pokemon page with rtk's createApi * Added back dispatch in GSP in demo repo * A change in query params constitutes a new page now * Improve performance by using another hook on server * Add detail page * New approach: split gsp and gssp and hydrate based on those * Added a second type of initial state handling with more explanations * Improved useMemo comment * Make sure hydrates work when staying on the same page * Add links to demo repo to test issue (seems like no issue) * Proper gipp fix (#512) * ESLint fix * Gipp testcase and example page in RTK repo (#514) * Add GIP to _app and add GIP in page to RTK repo * Added e2e test for RTK repo * Added testcase for GIAP and GIPP to wrapper * Consistent casing and formatting in comments Fix #493 #495 #496 Co-authored-by: voinik <[email protected]>
1 parent cd34b26 commit 8e098f7

33 files changed

+16364
-11395
lines changed

.yarnrc.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
nodeLinker: node-modules

README.md

Lines changed: 53 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -142,12 +142,12 @@ import {AppProps} from 'next/app';
142142
import {wrapper} from '../components/store';
143143

144144
const MyApp: FC<AppProps> = ({Component, ...rest}) => {
145-
const {store, props} = wrapper.useWrappedStore(rest);
146-
return (
147-
<Provider store={store}>
148-
<Component {...props.pageProps} />
149-
</Provider>
150-
);
145+
const {store, props} = wrapper.useWrappedStore(rest);
146+
return (
147+
<Provider store={store}>
148+
<Component {...props.pageProps} />
149+
</Provider>
150+
);
151151
};
152152
```
153153

@@ -183,20 +183,20 @@ import {HYDRATE} from 'next-redux-wrapper';
183183

184184
// create your reducer
185185
const reducer = (state = {tick: 'init'}, action) => {
186-
switch (action.type) {
187-
case HYDRATE:
188-
const stateDiff = diff(state, action.payload) as any;
189-
const wasBumpedOnClient = stateDiff?.page?.[0]?.endsWith('X'); // or any other criteria
190-
return {
191-
...state,
192-
...action.payload,
193-
page: wasBumpedOnClient ? state.page : action.payload.page, // keep existing state or use hydrated
194-
};
195-
case 'TICK':
196-
return {...state, tick: action.payload};
197-
default:
198-
return state;
199-
}
186+
switch (action.type) {
187+
case HYDRATE:
188+
const stateDiff = diff(state, action.payload) as any;
189+
const wasBumpedOnClient = stateDiff?.page?.[0]?.endsWith('X'); // or any other criteria
190+
return {
191+
...state,
192+
...action.payload,
193+
page: wasBumpedOnClient ? state.page : action.payload.page, // keep existing state or use hydrated
194+
};
195+
case 'TICK':
196+
return {...state, tick: action.payload};
197+
default:
198+
return state;
199+
}
200200
};
201201
```
202202

@@ -431,35 +431,30 @@ import {State} from '../components/reducer';
431431

432432
// Since you'll be passing more stuff to Page
433433
declare module 'next/dist/next-server/lib/utils' {
434-
export interface NextPageContext {
435-
store: Store<State>;
436-
}
434+
export interface NextPageContext {
435+
store: Store<State>;
436+
}
437437
}
438438

439439
class MyApp extends App<AppInitialProps> {
440+
public static getInitialProps = wrapper.getInitialAppProps(store => async context => {
441+
store.dispatch({type: 'TOE', payload: 'was set in _app'});
440442

441-
public static getInitialProps = wrapper.getInitialAppProps(store => async context => {
442-
443-
store.dispatch({type: 'TOE', payload: 'was set in _app'});
444-
445-
return {
446-
pageProps: {
447-
// https://nextjs.org/docs/advanced-features/custom-app#caveats
448-
...(await App.getInitialProps(context)).pageProps,
449-
// Some custom thing for all pages
450-
pathname: ctx.pathname,
451-
},
452-
};
453-
454-
});
443+
return {
444+
pageProps: {
445+
// https://nextjs.org/docs/advanced-features/custom-app#caveats
446+
...(await App.getInitialProps(context)).pageProps,
447+
// Some custom thing for all pages
448+
pathname: ctx.pathname,
449+
},
450+
};
451+
});
455452

456-
public render() {
457-
const {Component, pageProps} = this.props;
453+
public render() {
454+
const {Component, pageProps} = this.props;
458455

459-
return (
460-
<Component {...pageProps} />
461-
);
462-
}
456+
return <Component {...pageProps} />;
457+
}
463458
}
464459

465460
export default wrapper.withRedux(MyApp);
@@ -476,28 +471,24 @@ import App from 'next/app';
476471
import {wrapper} from '../components/store';
477472

478473
class MyApp extends App {
479-
static getInitialProps = wrapper.getInitialAppProps(store => async context => {
480-
481-
store.dispatch({type: 'TOE', payload: 'was set in _app'});
482-
483-
return {
484-
pageProps: {
485-
// https://nextjs.org/docs/advanced-features/custom-app#caveats
486-
...(await App.getInitialProps(context)).pageProps,
487-
// Some custom thing for all pages
488-
pathname: ctx.pathname,
489-
},
490-
};
474+
static getInitialProps = wrapper.getInitialAppProps(store => async context => {
475+
store.dispatch({type: 'TOE', payload: 'was set in _app'});
491476

492-
});
477+
return {
478+
pageProps: {
479+
// https://nextjs.org/docs/advanced-features/custom-app#caveats
480+
...(await App.getInitialProps(context)).pageProps,
481+
// Some custom thing for all pages
482+
pathname: ctx.pathname,
483+
},
484+
};
485+
});
493486

494-
render() {
495-
const {Component, pageProps} = this.props;
487+
render() {
488+
const {Component, pageProps} = this.props;
496489

497-
return (
498-
<Component {...pageProps} />
499-
);
500-
}
490+
return <Component {...pageProps} />;
491+
}
501492
}
502493

503494
export default wrapper.withRedux(MyApp);

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919
"lint:staged": "lint-staged --debug"
2020
},
2121
"devDependencies": {
22-
"eslint": "8.6.0",
23-
"eslint-config-ringcentral-typescript": "7.0.1",
22+
"eslint": "8.29.0",
23+
"eslint-config-ringcentral-typescript": "7.0.3",
2424
"husky": "7.0.4",
2525
"lerna": "4.0.0",
2626
"lint-staged": "11.1.2",

packages/demo-page/src/components/store.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import reducer, {State} from './reducer';
66
export const makeStore = (context: Context) => {
77
const store = createStore(reducer, applyMiddleware(logger));
88

9-
if (module.hot) {
10-
module.hot.accept('./reducer', () => {
9+
if ((module as any).hot) {
10+
(module as any).hot.accept('./reducer', () => {
1111
console.log('Replacing reducer');
1212
store.replaceReducer(require('./reducer').default);
1313
});

packages/demo-page/src/pages/_error.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@ const ErrorPage = ({page}: any) => (
77
<>
88
<p>This is an error page, {page}.</p>
99
<nav>
10-
<Link href="/">
11-
<a>Navigate to index</a>
12-
</Link>
10+
<Link href="/">Navigate to index</Link>
1311
</nav>
1412
</>
1513
);

packages/demo-page/src/pages/index.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,9 @@ const Page: NextPage<ConnectedPageProps> = ({custom}) => {
1515
return (
1616
<div className="index">
1717
<pre>{JSON.stringify({page, custom}, null, 2)}</pre>
18-
<Link href="/other">
19-
<a>Navigate</a>
20-
</Link>
18+
<Link href="/other">Navigate</Link>
2119
{' | '}
22-
<Link href="/error">
23-
<a>Navigate to error</a>
24-
</Link>
20+
<Link href="/error">Navigate to error</Link>
2521
</div>
2622
);
2723
};

packages/demo-page/src/pages/other.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,8 @@ const OtherPage: NextPage<State> = () => {
2424
<pre>{JSON.stringify({page}, null, 2)}</pre>
2525
<nav>
2626
<button onClick={bump}>bump</button>
27-
<Link href="/">
28-
<a>Navigate to index</a>
29-
</Link>
30-
<Link href="/other2">
31-
<a>Navigate to other 2</a>
32-
</Link>
27+
<Link href="/">Navigate to index</Link>
28+
<Link href="/other2">Navigate to other 2</Link>
3329
</nav>
3430
</div>
3531
);

packages/demo-page/src/pages/other2.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,8 @@ const OtherPage: NextPage<State> = () => {
2424
<pre>{JSON.stringify({page}, null, 2)}</pre>
2525
<nav>
2626
<button onClick={bump}>bump</button>
27-
<Link href="/">
28-
<a>Navigate to index</a>
29-
</Link>
30-
<Link href="/other">
31-
<a>Navigate to other</a>
32-
</Link>
27+
<Link href="/">Navigate to index</Link>
28+
<Link href="/other">Navigate to other</Link>
3329
</nav>
3430
</div>
3531
);

packages/demo-page/src/pages/pageProps.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@ const PropsPage: NextPage<State> = props => {
1010
<p>Using Next.js default prop in a wrapped component.</p>
1111
<pre>{JSON.stringify(props)}</pre>
1212
<nav>
13-
<Link href="/">
14-
<a>Navigate to index</a>
15-
</Link>
13+
<Link href="/">Navigate to index</Link>
1614
</nav>
1715
</div>
1816
);

packages/demo-redux-toolkit/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"start": "next --port=6060"
99
},
1010
"dependencies": {
11-
"@reduxjs/toolkit": "1.6.2",
11+
"@reduxjs/toolkit": "1.8.6",
1212
"next-redux-wrapper": "*",
1313
"react": "17.0.2",
1414
"react-dom": "17.0.2",

0 commit comments

Comments
 (0)