Skip to content

Commit

Permalink
Merge 8ab5d3c into 726d0d1
Browse files Browse the repository at this point in the history
  • Loading branch information
kirill-konshin committed Feb 1, 2023
2 parents 726d0d1 + 8ab5d3c commit 54011bb
Show file tree
Hide file tree
Showing 58 changed files with 11,826 additions and 16,666 deletions.
986 changes: 342 additions & 644 deletions README.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,6 @@
"license": "MIT",
"packageManager": "yarn@3.0.2",
"resolutions": {
"@types/react": "17.0.37"
"@types/react": "18.0.27"
}
}
1 change: 0 additions & 1 deletion packages/demo-page/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/// <reference types="next" />
/// <reference types="next/types/global" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
Expand Down
5 changes: 5 additions & 0 deletions packages/demo-page/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/** @type {import('next').NextConfig} */
module.exports = {
// transpilePackages: ['next-redux-wrapper'], // @see https://nextjs.org/docs/advanced-features/compiler#module-transpilation
swcMinify: true,
};
10 changes: 5 additions & 5 deletions packages/demo-page/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,19 @@
"dependencies": {
"jsondiffpatch": "0.4.1",
"next-redux-wrapper": "*",
"react": "17.0.2",
"react-dom": "17.0.2",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-redux": "7.2.6",
"redux": "4.1.2",
"redux-logger": "3.0.6"
},
"devDependencies": {
"@playwright/test": "1.17.1",
"@types/react": "17.0.37",
"@types/react-dom": "17.0.11",
"@types/react": "18.0.27",
"@types/react-dom": "18.0.10",
"@types/react-redux": "7.1.20",
"@types/redux-logger": "3.0.9",
"next": "12.0.4",
"next": "13.1.6",
"next-redux-wrapper-configs": "*",
"playwright": "1.17.1",
"rimraf": "3.0.2",
Expand Down
14 changes: 0 additions & 14 deletions packages/demo-page/src/components/reducer.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,11 @@
import {AnyAction} from 'redux';
import {HYDRATE} from 'next-redux-wrapper';
import {diff} from 'jsondiffpatch';

export interface State {
page: string;
}

const reducer = (state: State = {page: 'init'}, action: AnyAction) => {
switch (action.type) {
case HYDRATE:
const stateDiff = diff(state, action.payload) as any;
const wasBumpedOnClient = stateDiff?.page?.[0]?.endsWith('X');
console.log('HYDRATE action handler', {
stateDiff,
wasBumpedOnClient,
});
return {
...state,
...action.payload,
page: wasBumpedOnClient ? state.page : action.payload.page,
};
case 'PAGE':
return {...state, page: action.payload};
case 'BUMP':
Expand Down
6 changes: 3 additions & 3 deletions packages/demo-page/src/components/store.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {createStore, applyMiddleware, Store} from 'redux';
import logger from 'redux-logger';
import {createWrapper, Context} from 'next-redux-wrapper';
import {createWrapper} from 'next-redux-wrapper';
import reducer, {State} from './reducer';

export const makeStore = (context: Context) => {
const store = createStore(reducer, applyMiddleware(logger));
export const makeStore = ({context, reduxWrapperMiddleware}) => {
const store = createStore(reducer, applyMiddleware(...[process.browser ? logger : null, reduxWrapperMiddleware].filter(Boolean)));

if ((module as any).hot) {
(module as any).hot.accept('./reducer', () => {
Expand Down
12 changes: 10 additions & 2 deletions packages/demo-page/src/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import React, {FC} from 'react';
import {AppProps} from 'next/app';
import {Provider} from 'react-redux';
import {wrapper} from '../components/store';

const MyApp: FC<AppProps> = ({Component, pageProps}) => <Component {...pageProps} />;
const MyApp: FC<AppProps> = function MyApp({Component, pageProps}) {
const store = wrapper.useStore();
return (
<Provider store={store}>
<Component {...pageProps} />
</Provider>
);
};

export default wrapper.withRedux(MyApp);
export default MyApp;
4 changes: 2 additions & 2 deletions packages/demo-page/src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ export interface ConnectedPageProps {
}

// Page itself is not connected to Redux Store, it has to render Provider to allow child components to connect to Redux Store
const Page: NextPage<ConnectedPageProps> = ({custom}) => {
const Page: NextPage<ConnectedPageProps> = ({custom, ...props}: any) => {
wrapper.useHydration(props);
const {page} = useSelector<State, State>(state => state);
return (
<div className="index">
Expand All @@ -23,7 +24,6 @@ const Page: NextPage<ConnectedPageProps> = ({custom}) => {
};

export const getServerSideProps = wrapper.getServerSideProps(store => async ({req}) => {
console.log('2. Page.getServerSideProps uses the store to dispatch things');
store.dispatch({
type: 'PAGE',
payload: 'was set in index page ' + req.url,
Expand Down
4 changes: 2 additions & 2 deletions packages/demo-page/src/pages/other.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ import {State} from '../components/reducer';
import {wrapper} from '../components/store';

export const getStaticProps = wrapper.getStaticProps(store => async ({previewData}) => {
console.log('2. Page.getStaticProps uses the store to dispatch things');
store.dispatch({
type: 'PAGE',
payload: 'was set in other page ' + JSON.stringify({previewData}),
});
return {props: {}};
});

const OtherPage: NextPage<State> = () => {
const OtherPage: NextPage<State> = props => {
wrapper.useHydration(props);
const {page} = useSelector<State, State>(state => state);
const dispatch = useDispatch();
const bump = () => dispatch({type: 'BUMP'});
Expand Down
4 changes: 2 additions & 2 deletions packages/demo-page/src/pages/other2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ import {State} from '../components/reducer';
import {wrapper} from '../components/store';

export const getStaticProps = wrapper.getStaticProps(store => async ({previewData}) => {
console.log('2. Page.getStaticProps uses the store to dispatch things');
store.dispatch({
type: 'PAGE',
payload: 'was set in other (SECOND) page ' + JSON.stringify({previewData}),
});
return {props: {}};
});

const OtherPage: NextPage<State> = () => {
const OtherPage: NextPage<State> = props => {
wrapper.useHydration(props);
const {page} = useSelector<State, State>(state => state);
const dispatch = useDispatch();
const bump = () => dispatch({type: 'BUMP'});
Expand Down
3 changes: 2 additions & 1 deletion packages/demo-page/src/pages/pageProps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {State} from '../components/reducer';
import {wrapper} from '../components/store';

const PropsPage: NextPage<State> = props => {
wrapper.useHydration(props);
return (
<div className="pageProps">
<p>Using Next.js default prop in a wrapped component.</p>
Expand All @@ -16,7 +17,7 @@ const PropsPage: NextPage<State> = props => {
);
};

PropsPage.getInitialProps = wrapper.getInitialPageProps(store => async () => ({
(PropsPage as any).getInitialProps = wrapper.getInitialPageProps(store => async () => ({
prop: 'foo',
}));

Expand Down
16 changes: 8 additions & 8 deletions packages/demo-page/tests/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import {test, expect, Page} from '@playwright/test';

const openPage = (page: Page, url = '/') => page.goto(`http://localhost:4000${url}`);
const openPage = (page: Page, baseURL: string | undefined, url = '/') => page.goto(`${baseURL}${url}`);

test('shows the page', async ({page}) => {
await openPage(page);
test('shows the page', async ({page, baseURL}) => {
await openPage(page, baseURL);

await page.waitForSelector('div.index');

await expect(page.locator('body')).toContainText('"page": "was set in index page /"');
await expect(page.locator('body')).toContainText('"custom": "custom"');
});

test('clicks the button', async ({page}) => {
await openPage(page, '/other');
test('clicks the button', async ({page, baseURL}) => {
await openPage(page, baseURL, '/other');

await page.waitForSelector('div.other');

Expand All @@ -26,10 +26,10 @@ test('clicks the button', async ({page}) => {
await expect(page.locator('body')).toContainText('"custom": "custom"');
});

test('initial page props', async ({page}) => {
await openPage(page, '/pageProps');
test('initial page props', async ({page, baseURL}) => {
await openPage(page, baseURL, '/pageProps');

await page.waitForSelector('div.pageProps');

await expect(page.locator('body')).toContainText('{"prop":"foo"}');
await expect(page.locator('body')).toContainText('"prop":"foo"');
});
1 change: 0 additions & 1 deletion packages/demo-redux-toolkit/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/// <reference types="next" />
/// <reference types="next/types/global" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
Expand Down
5 changes: 5 additions & 0 deletions packages/demo-redux-toolkit/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/** @type {import('next').NextConfig} */
module.exports = {
// transpilePackages: ['next-redux-wrapper'], // @see https://nextjs.org/docs/advanced-features/compiler#module-transpilation
swcMinify: true,
};
11 changes: 7 additions & 4 deletions packages/demo-redux-toolkit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@
"dependencies": {
"@reduxjs/toolkit": "1.8.6",
"next-redux-wrapper": "*",
"react": "17.0.2",
"react-dom": "17.0.2",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-redux": "7.2.6",
"redux": "4.1.2"
"redux": "4.1.2",
"redux-logger": "3.0.6"
},
"devDependencies": {
"@playwright/test": "1.17.1",
"next": "12.0.4",
"@types/react": "18.0.27",
"@types/react-dom": "18.0.10",
"next": "13.1.6",
"playwright": "1.17.1"
},
"license": "MIT"
Expand Down
23 changes: 11 additions & 12 deletions packages/demo-redux-toolkit/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,34 @@
import React from 'react';
import React, {FC} from 'react';
import {Provider} from 'react-redux';
import App, {AppProps} from 'next/app';
import {fetchSystem, wrapper} from '../store';

interface PageProps {
pageProps: {
id: number;
};
}
const MyApp: FC<AppProps> = function MyApp({Component, pageProps}) {
console.log('rest: ', pageProps);

const MyApp = ({Component, ...rest}: Omit<AppProps, 'pageProps'> & PageProps) => {
console.log('rest: ', rest);
const {store, props} = wrapper.useWrappedStore(rest);
const store = wrapper.useStore();

return (
<Provider store={store}>
<h1>PageProps.id: {rest.pageProps.id}</h1>
<Component {...props.pageProps} />
<h1>PageProps.id: {pageProps.id}</h1>
<Component {...pageProps} />
</Provider>
);
};

MyApp.getInitialProps = wrapper.getInitialAppProps(store => async (appCtx): Promise<PageProps> => {
//FIXME This is not a recommended approach, only used here for demo purposes
(MyApp as any).getInitialProps = wrapper.getInitialAppProps(store => async appCtx => {
// You have to do dispatches first, before...
await store.dispatch(fetchSystem());

// ...before calling (and awaiting!!!!) the children's getInitialProps
// @see https://nextjs.org/docs/advanced-features/custom-app#caveats
const childrenGip = await App.getInitialProps(appCtx);

return {
pageProps: {
// And you have to spread the children's GIP result into pageProps
// @see https://nextjs.org/docs/advanced-features/custom-app#caveats
...childrenGip.pageProps,
id: 42,
},
Expand Down
6 changes: 4 additions & 2 deletions packages/demo-redux-toolkit/pages/detail/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import {
wrapper,
} from '../../store';

const Page: NextPage<InferGetServerSidePropsType<typeof getServerSideProps>> = ({serverTimestamp}) => {
const Page : NextPage<InferGetServerSidePropsType<typeof getServerSideProps>> = function Detail ({serverTimestamp, ...rest}) {
wrapper.useHydration(rest);

console.log('State on render', useStore().getState());
console.log('Timestamp on server: ', serverTimestamp);
const dispatch = useDispatch();
Expand All @@ -25,7 +27,7 @@ const Page: NextPage<InferGetServerSidePropsType<typeof getServerSideProps>> = (
console[pageSummary ? 'info' : 'warn']('Rendered pageName: ', pageSummary);

if (!pageSummary || !pageId || !data) {
throw new Error('Whoops! We do not have the pageId and pageSummary selector data!');
return <div>Loading</div>;
}

return (
Expand Down
5 changes: 3 additions & 2 deletions packages/demo-redux-toolkit/pages/gipp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ interface Props {
name: string;
}

const Page: NextPage<Props> = ({name}) => {
const Page: NextPage<Props> = ({name, ...props}: any) => {
wrapper.useHydration(props);
console.log('State on render', useStore().getState());
const dispatch = useDispatch();
const testData = useSelector(selectGippPageTestData);
Expand All @@ -19,7 +20,7 @@ const Page: NextPage<Props> = ({name}) => {
console[testData ? 'info' : 'warn']('Rendered testData: ', testData);

if (!testData || !data) {
throw new Error('Whoops! We do not have the data and testData selector data!');
return <div>Loading...</div>;
}

return (
Expand Down
5 changes: 3 additions & 2 deletions packages/demo-redux-toolkit/pages/pokemon/[pokemon].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import {useRouter} from 'next/router';
import {wrapper, pokemonApi, useGetPokemonByNameQuery} from '../../store';
import {useStore} from 'react-redux';

export default function Pokemon() {
export default function Pokemon(props: any) {
wrapper.useHydration(props);
const {query} = useRouter();

console.log('State on render', useStore().getState());
const {data} = useGetPokemonByNameQuery(query.pokemon as string); // data is undefined for the first render

if (!data) {
throw new Error('Whoops! We do not have the data selector data!');
return <div>Loading</div>;
}

return <div>Name: {data?.name}</div>;
Expand Down
7 changes: 5 additions & 2 deletions packages/demo-redux-toolkit/pages/subject/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ import Link from 'next/link';
import {InferGetServerSidePropsType, NextPage} from 'next';
import {fetchSubject, selectSubjectPageId, selectSubjectPageName, selectSubjectPageStateTimestamp, wrapper} from '../../store';

const Page: NextPage<InferGetServerSidePropsType<typeof getServerSideProps>> = ({serverTimestamp}) => {
const Page: NextPage<InferGetServerSidePropsType<typeof getServerSideProps>> = function Subject({serverTimestamp, ...props}) {
const {hydrating} = wrapper.useHydration(props);

console.log('State on render', useStore().getState());
console.log('Timestamp on server: ', serverTimestamp);
console.log('Hydrating:', hydrating);
const dispatch = useDispatch();
const pageId = useSelector(selectSubjectPageId);
const pageName = useSelector(selectSubjectPageName);
Expand All @@ -15,7 +18,7 @@ const Page: NextPage<InferGetServerSidePropsType<typeof getServerSideProps>> = (
console[pageName ? 'info' : 'warn']('Rendered pageName: ', pageName);

if (!pageName || !pageId) {
throw new Error('Whoops! We do not have the pageId and pageName selector data!');
return <div>Loading</div>;
}

return (
Expand Down
Loading

0 comments on commit 54011bb

Please sign in to comment.