Skip to content

Commit

Permalink
Fix hot reloading issues by removing the store from window
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielOrtel committed Feb 11, 2021
1 parent 193e2a3 commit 4c97e10
Show file tree
Hide file tree
Showing 4 changed files with 15 additions and 24 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,6 @@ The `createWrapper` function accepts `makeStore` as its first argument. The `mak
`createWrapper` also optionally accepts a config object as a second parameter:
- `storeKey` (optional, string) : the key used on `window` to persist the store on the client
- `debug` (optional, boolean) : enable debug logging
- `serializeState` and `deserializeState`: custom functions for serializing and deserializing the redux state, see
[Custom serialization and deserialization](#custom-serialization-and-deserialization).
Expand Down
20 changes: 8 additions & 12 deletions packages/wrapper/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
} from 'next';

export const HYDRATE = '__NEXT_REDUX_WRAPPER_HYDRATE__';
export const STOREKEY = '__NEXT_REDUX_WRAPPER_STORE__';

const getIsServer = () => typeof window === 'undefined';

Expand All @@ -22,19 +21,16 @@ const getDeserializedState = <S extends Store>(initialState: any, {deserializeSt
const getSerializedState = <S extends Store>(state: any, {serializeState}: Config<S> = {}) =>
serializeState ? serializeState(state) : state;

const getStoreKey = <S extends Store>({storeKey}: Config<S> = {}) => storeKey || STOREKEY;

export declare type MakeStore<S extends Store> = (context: Context) => S;

export interface InitStoreOptions<S extends Store> {
makeStore: MakeStore<S>;
context: Context;
config: Config<S>;
}

const initStore = <S extends Store>({makeStore, context, config}: InitStoreOptions<S>): S => {
const storeKey = getStoreKey(config);
let store: any;

const initStore = <S extends Store>({makeStore, context}: InitStoreOptions<S>): S => {
const createStore = () => makeStore(context);

if (getIsServer()) {
Expand All @@ -48,15 +44,16 @@ const initStore = <S extends Store>({makeStore, context, config}: InitStoreOptio
if (!req.__nextReduxWrapperStore) req.__nextReduxWrapperStore = createStore();
return req.__nextReduxWrapperStore;
}

return createStore();
}

// Memoize store if client
if (!(storeKey in window)) {
(window as any)[storeKey] = createStore();
if (!store) {
store = createStore();
}

return (window as any)[storeKey];
return store;
};

export const createWrapper = <S extends Store>(makeStore: MakeStore<S>, config: Config<S> = {}) => {
Expand All @@ -67,7 +64,7 @@ export const createWrapper = <S extends Store>(makeStore: MakeStore<S>, config:
callback: Callback<S, any>;
context: any;
}): Promise<WrapperProps> => {
const store = initStore({context, makeStore, config});
const store = initStore({context, makeStore});

if (config.debug) console.log(`1. getProps created store with state`, store.getState());

Expand Down Expand Up @@ -141,7 +138,7 @@ export const createWrapper = <S extends Store>(makeStore: MakeStore<S>, config:
const initialStateFromGSPorGSSR = props?.pageProps?.initialState;

if (!this.store) {
this.store = initStore({makeStore, config, context});
this.store = initStore({makeStore, context});

if (config.debug)
console.log('4. WrappedApp created new store with', displayName, {
Expand Down Expand Up @@ -232,7 +229,6 @@ export type Context = NextPageContext | AppContext | GetStaticPropsContext | Get
export interface Config<S extends Store> {
serializeState?: (state: ReturnType<S['getState']>) => any;
deserializeState?: (state: any) => ReturnType<S['getState']>;
storeKey?: string;
debug?: boolean;
}

Expand Down
16 changes: 6 additions & 10 deletions packages/wrapper/tests/client.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,19 @@ import {DummyComponent, wrapper, child, makeStore} from './testlib';
import {createWrapper} from '../src';
import {Store} from 'redux';

const w: {testStoreKey?: Store} = window as any;
let store: Store;

const defaultState = {reduxStatus: 'init'};

describe('client integration', () => {
afterEach(() => {
delete w.testStoreKey;
});

describe('existing store is taken from window', () => {
beforeEach(() => {
w.testStoreKey = makeStore();
store = makeStore();
});

test('withRedux', async () => {
const WrappedPage: any = wrapper.withRedux(DummyComponent);
expect(child(<WrappedPage initialState={w.testStoreKey?.getState()} />)).toEqual(
expect(child(<WrappedPage initialState={store.getState()} />)).toEqual(
'{"props":{},"state":{"reduxStatus":"init"}}',
);
});
Expand All @@ -38,11 +34,11 @@ describe('client integration', () => {
});
});

test('store is available in window when created', async () => {
const wrapper = createWrapper(makeStore, {storeKey: 'testStoreKey'});
test('store is available when calling getInitialProps client-side', async () => {
const wrapper = createWrapper(makeStore);
const Page = () => null;
Page.getInitialProps = wrapper.getInitialPageProps(store => () => null);
await wrapper.withRedux(Page)?.getInitialProps({} as any);
expect(w.testStoreKey?.getState()).toEqual(defaultState);
expect(store.getState()).toEqual(defaultState);
});
});
2 changes: 1 addition & 1 deletion packages/wrapper/tests/testlib.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const reducer = (state: State = {reduxStatus: 'init'}, action: AnyAction)

export const makeStore = () => createStore(reducer, undefined, applyMiddleware(promiseMiddleware));

export const wrapper = createWrapper(makeStore, {storeKey: 'testStoreKey'});
export const wrapper = createWrapper(makeStore);

export const DummyComponent = (props: any) => {
const state = useSelector((state: State) => state);
Expand Down

0 comments on commit 4c97e10

Please sign in to comment.