Skip to content

Commit

Permalink
Merge 1469991 into 5ac79cb
Browse files Browse the repository at this point in the history
  • Loading branch information
voinik committed Dec 16, 2022
2 parents 5ac79cb + 1469991 commit 485d832
Show file tree
Hide file tree
Showing 9 changed files with 15,529 additions and 11,195 deletions.
32 changes: 28 additions & 4 deletions packages/demo-redux-toolkit/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,39 @@
import React, {FC} from 'react';
import React from 'react';
import {Provider} from 'react-redux';
import {AppProps} from 'next/app';
import {wrapper} from '../store';
import App, {AppProps} from 'next/app';
import {fetchSystem, wrapper} from '../store';

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

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

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

MyApp.getInitialProps = wrapper.getInitialAppProps(store => async (appCtx): Promise<PageProps> => {
// You have to do dispatches first, before...
await store.dispatch(fetchSystem());

// ...before calling (and awaiting!!!!) the children's getInitialProps
const childrenGip = await App.getInitialProps(appCtx);
return {
pageProps: {
// And you have to spread the children's GIP result into pageProps
...childrenGip.pageProps,
id: 42,
},
};
});

export default MyApp;
5 changes: 4 additions & 1 deletion packages/demo-redux-toolkit/pages/detail/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
selectDetailPageId,
selectDetailPageStateTimestamp,
selectDetailPageSummary,
selectSystemSource,
wrapper,
} from '../../store';

Expand All @@ -19,6 +20,7 @@ const Page: NextPage<InferGetServerSidePropsType<typeof getServerSideProps>> = (
const pageSummary = useSelector(selectDetailPageSummary);
const stateTimestamp = useSelector(selectDetailPageStateTimestamp);
const data = useSelector(selectDetailPageData);
const source = useSelector(selectSystemSource);

console[pageSummary ? 'info' : 'warn']('Rendered pageName: ', pageSummary);

Expand All @@ -31,6 +33,7 @@ const Page: NextPage<InferGetServerSidePropsType<typeof getServerSideProps>> = (
<div style={{backgroundColor: 'pink', padding: '20px'}}>Timestamp on server: {serverTimestamp}</div>
<div style={{backgroundColor: 'lavender', padding: '20px'}}>Timestamp in state: {stateTimestamp}</div>
<div className={`page${pageId}`}>
<h1>System source: {source}</h1>
<h3>{pageSummary}</h3>
<Link href="/subject/1">Go id=1</Link>
&nbsp;&nbsp;&nbsp;&nbsp;
Expand All @@ -40,7 +43,7 @@ const Page: NextPage<InferGetServerSidePropsType<typeof getServerSideProps>> = (
&nbsp;&nbsp;&nbsp;&nbsp;
<Link href="/detail/2">Go to details id=2</Link>
&nbsp;&nbsp;&nbsp;&nbsp;
<Link href="/gipp">Go to gip page</Link>
<Link href="/gipp">Go to gipp page</Link>
&nbsp;&nbsp;&nbsp;&nbsp;
<Link href="/pokemon/pikachu">Go to Pokemon</Link>
&nbsp;&nbsp;&nbsp;&nbsp;
Expand Down
13 changes: 10 additions & 3 deletions packages/demo-redux-toolkit/pages/gipp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@ import React from 'react';
import {useDispatch, useSelector, useStore} from 'react-redux';
import Link from 'next/link';
import {NextPage} from 'next';
import {fetchGipp, selectGippPageData, selectGippPageStateTimestamp, selectGippPageTestData, wrapper} from '../store';
import {fetchGipp, selectGippPageData, selectGippPageStateTimestamp, selectGippPageTestData, selectSystemSource, wrapper} from '../store';

const Page: NextPage = () => {
interface Props {
name: string;
}

const Page: NextPage<Props> = ({name}) => {
console.log('State on render', useStore().getState());
const dispatch = useDispatch();
const testData = useSelector(selectGippPageTestData);
const stateTimestamp = useSelector(selectGippPageStateTimestamp);
const data = useSelector(selectGippPageData);
const source = useSelector(selectSystemSource);

console[testData ? 'info' : 'warn']('Rendered testData: ', testData);

Expand All @@ -21,7 +26,9 @@ const Page: NextPage = () => {
<>
<div style={{backgroundColor: 'lavender', padding: '20px'}}>Timestamp in state: {stateTimestamp}</div>
<div className={`page${1}`}>
<h1>System source: {source}</h1>
<h3>{testData}</h3>
<h3>Page name: {name}</h3>
<Link href="/subject/1">Go id=1</Link>
&nbsp;&nbsp;&nbsp;&nbsp;
<Link href="/subject/2">Go id=2</Link>
Expand All @@ -41,7 +48,7 @@ const Page: NextPage = () => {

Page.getInitialProps = wrapper.getInitialPageProps(store => async () => {
await store.dispatch(fetchGipp());
return {};
return {name: 'GIPP'};
});

export default Page;
2 changes: 1 addition & 1 deletion packages/demo-redux-toolkit/pages/subject/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const Page: NextPage<InferGetServerSidePropsType<typeof getServerSideProps>> = (
&nbsp;&nbsp;&nbsp;&nbsp;
<Link href="/detail/2">Go to details id=2</Link>
&nbsp;&nbsp;&nbsp;&nbsp;
<Link href="/gipp">Go to gip page</Link>
<Link href="/gipp">Go to gipp page</Link>
&nbsp;&nbsp;&nbsp;&nbsp;
<Link href="/pokemon/pikachu">Go to Pokemon</Link>
&nbsp;&nbsp;&nbsp;&nbsp;
Expand Down
57 changes: 57 additions & 0 deletions packages/demo-redux-toolkit/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,40 @@ import {createApi, fetchBaseQuery} from '@reduxjs/toolkit/query/react';
import {Action, combineReducers} from 'redux';
import {createWrapper, HYDRATE} from 'next-redux-wrapper';

// System model
interface SystemData {
source: string;
}

interface SystemState {
data: SystemData | null;
}

const initialSystemState: SystemState = {
data: null,
};

// Subject page slice approach
const systemSlice = createSlice({
name: 'system',
initialState: initialSystemState,
reducers: {
systemLoaded(state, {payload}: PayloadAction<SystemState>) {
state.data = payload.data;
},
},
extraReducers: {
[HYDRATE]: (state, action) => {
console.log('HYDRATE system', action.payload);

return {
...state,
...action.payload.system,
};
},
},
});

// Subject page model
interface SubjectPageData {
id: string;
Expand Down Expand Up @@ -149,6 +183,7 @@ const reducers = {
[subjectPageSlice.name]: subjectPageSlice.reducer,
[detailPageSlice.name]: detailPageSlice.reducer,
[gippPageSlice.name]: gippPageSlice.reducer,
[systemSlice.name]: systemSlice.reducer,
[pokemonApi.reducerPath]: pokemonApi.reducer,
};

Expand All @@ -167,6 +202,21 @@ type AppThunk<ReturnType = void> = ThunkAction<ReturnType, AppState, unknown, Ac

export const wrapper = createWrapper<AppStore>(makeStore);

// System thunk
export const fetchSystem = (): AppThunk => async dispatch => {
const timeoutPromise = (timeout: number) => new Promise(resolve => setTimeout(resolve, timeout));

await timeoutPromise(200);

dispatch(
systemSlice.actions.systemLoaded({
data: {
source: 'GIAP',
},
}),
);
};

// Subject page thunk
export const fetchSubject =
(id: string): AppThunk =>
Expand Down Expand Up @@ -222,6 +272,13 @@ export const fetchGipp = (): AppThunk => async dispatch => {
);
};

// System selectors
const systemSliceSelector = (state: AppState): SystemState => state.system;

const selectSystemData = createSelector(systemSliceSelector, s => s.data);

export const selectSystemSource = createSelector(selectSystemData, s => s?.source);

// Subject page selectors
const subjectPageSliceSelector = (state: AppState): SubjectPageState => state.subjectPage;

Expand Down
68 changes: 62 additions & 6 deletions packages/demo-redux-toolkit/tests/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,47 @@ const openPage = (page: Page, url = '/') => page.goto(`http://localhost:6060${ur
test('shows the page', async ({page}) => {
await openPage(page);

// Problem page 1
await page.click('text=Go to problem pages');

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

await expect(page.locator('body')).toContainText('PageProps.id: 42');
await expect(page.locator('body')).toContainText('Subject 1');

// Problem page 2
await page.click('text=GO id=2');

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

await expect(page.locator('body')).toContainText('PageProps.id: 42');
await expect(page.locator('body')).toContainText('Subject 2');

await page.click('text=GO id=1');

// Detail page 1
await page.click('text=Go to details id=1');
await page.waitForSelector('div.page1');

await expect(page.locator('body')).toContainText('Subject 1');
await expect(page.locator('body')).toContainText('PageProps.id: 42');
await expect(page.locator('body')).toContainText('System source: GIAP');
await expect(page.locator('body')).toContainText('This is the summary for the page with id 1');

// Detail page 2
await page.click('text=Go to details id=2');
await page.waitForSelector('div.page2');

await expect(page.locator('body')).toContainText('PageProps.id: 42');
await expect(page.locator('body')).toContainText('System source: GIAP');
await expect(page.locator('body')).toContainText('This is the summary for the page with id 2');

// Gipp page
await page.click('text=Go to gipp page');
await page.waitForSelector('div.page2');

await expect(page.locator('body')).toContainText('PageProps.id: 42');
await expect(page.locator('body')).toContainText('System source: GIAP');
await expect(page.locator('body')).toContainText('This is the test data for the gipp page');
await expect(page.locator('body')).toContainText('Page name: GIPP');
});

test('server rendered', async () => {
test('server rendered subject page', async () => {
const browser = await chromium.launch();

const context = await browser.newContext({
Expand All @@ -38,3 +59,38 @@ test('server rendered', async () => {

await browser.close();
});

test('server rendered detail page', async () => {
const browser = await chromium.launch();

const context = await browser.newContext({
javaScriptEnabled: false,
});
const page = await context.newPage();

await openPage(page, '/detail/1');

await expect(page.locator('body')).toContainText('PageProps.id: 42');
await expect(page.locator('body')).toContainText('System source: GIAP');
await expect(page.locator('body')).toContainText('This is the summary for the page with id 1');

await browser.close();
});

test('server rendered gipp page', async () => {
const browser = await chromium.launch();

const context = await browser.newContext({
javaScriptEnabled: false,
});
const page = await context.newPage();

await openPage(page, '/gipp');

await expect(page.locator('body')).toContainText('PageProps.id: 42');
await expect(page.locator('body')).toContainText('System source: GIAP');
await expect(page.locator('body')).toContainText('This is the test data for the gipp page');
await expect(page.locator('body')).toContainText('Page name: GIPP');

await browser.close();
});
2 changes: 1 addition & 1 deletion packages/wrapper/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ export const createWrapper = <S extends Store>(makeStore: MakeStore<S>, config:
if ('getState' in context) {
return callback && callback(context as any);
}
return makeProps({callback, context, addStoreToContext: true});
return await makeProps({callback, context, addStoreToContext: true});
};

const getInitialAppProps =
Expand Down
Loading

0 comments on commit 485d832

Please sign in to comment.