Easy-Peasy / NextJS / React maybeGetServerSnapshot is not a function

222 Views Asked by At

Running the latest easy-peasy (5.2.0) along with the lates major versions of NextJS (12.1.6) and React (18.1.0) causes easy-peasy to throw an error

TypeError: maybeGetServerSnapshot is not a function` when calling their native `useStoreState`.
export default function Counter() {
> 4 |   const count = useStoreState((state) => state.counter.count);
    |                               ^
  5 |   const increment = useStoreActions((actions) => actions.counter.increment);

After lots of looking I have found no other posts about this issue, although I see similar issues with other storage options like zustand https://github.com/pmndrs/zustand/issues/963, although this seems like a red herring.

The error I am facing seems to be an internal NextJS issue with their storage sync to react from easy-peasy but at the end of the day this error does not return a lot of information and I am pretty stuck.

This example of using NextJS with easy-peasy is referenced in quite a few places, and works great https://codesandbox.io/s/c24rg. However, this project uses the last major version of each project respectively. I have a hard requirement of staying at my specified major version or React and Next. Any insight into this issue would be a lot of help.

Edit 1:

Adding SSR state

export function getServerSideProps() {
    const store = initializeStore()

    const data = ['apple', 'pear', 'orange', 'nuts']
    store.getActions().inventory.setItems(data)

    return {
        props: {
            ssrStoreState: store.getState()
        }
    }
}

Initialize client side state

export default function WrappedApp({ Component, pageProps }) {
    const store = useStore(pageProps.ssrStoreState)

    return (
        <StoreProvider store={store}>
            <Component {...pageProps} />
        </StoreProvider>
    )
}

Use state effect to get data

import { useStoreState, useStoreActions } from "easy-peasy";

export default function Counter() {
  const count = useStoreState((state) => state.counter.count);
  const increment = useStoreActions((actions) => actions.counter.increment);

  return (
    <div style={{ margin: "2rem" }}>
      <h1>Counter</h1>
      <p>value = {count}</p>
      <button onClick={increment}>Increment counter</button>
    </div>
  );
}

Custom store instantiation for SSR to client side synchronization Found in the store/store file


function initStore(preloadedState = initialState) {
    return createStore(
        persist(
            storeModel,
            { allow: ['shop'] }
        ),
        { initialState: preloadedState }
    )
}

export const initializeStore = (preloadedState) => {
    let _store = store ?? initStore(preloadedState)

    // After navigating to a page with an initial Redux state, merge that state
    // with the current state in the store, and create a new store
    if (preloadedState && store) {
        _store = initStore({
            ...store.getState(),
            ...preloadedState,
        })
        // Reset the current store
        store = undefined
    }

    // For SSG and SSR always create a new store
    if (typeof window === 'undefined') return _store
    // Create the store once in the client
    if (!store) store = _store

    return _store
}

export function useStore(initialState) {
    const store = useMemo(() => initializeStore(initialState), [initialState])
    return store
}
1

There are 1 best solutions below

0
JAM On

SSR does not work properly with [email protected] and NextJS with React 18.

It is fixed in the latest release of easy-peasy (version 6.0.0).