Seems to work fine with Next.js 4. Has problems with hot reloading in Next.js 5.
Forked from next-redux-wrapper
npm install next-spaceace-wrapper
Wrapper should be attached your page components (located in your project's /pages
). For safety it is recommended that you wrap all pages, whether they use SpaceAce or not.
Here is an example minimal setup:
import React, {Component} from "react";
import withSpace from "next-spaceace-wrapper";
/**
* @param {object} initialState
* @param {boolean} options.isServer indicates whether it is a server side or client side
* @param {Request} options.req NodeJS Request object (if any)
* @param {boolean} options.debug User-defined debug mode param
* @param {string} options.spaceKey This key will be used to preserve the root space in global namespace for safe HMR
*/
const makeRootSpace = () => {
return new Space({ env: process.env.NODE_ENV });
};
class Page extends Component {
static getInitialProps({space, isServer, pathname, query}) {
space.setState({ foo: bar }); // component will be able to read from space's state when rendered
return { custom: 'custom' }; // you can also pass some additional custom props to components
}
render() {
const { space } = this.props;
const rootSpace = space.getRootSpace();
return (
<div>
<div>Value from page’s Space {space.state.foo}</div>
<div>Value from root space {rootSpace.state.env}</div>
<div>Prop from getInitialProps {this.props.custom}</div>
</div>
)
}
}
// It’s recommended to import `makeRootSpace` from a speparate module
// so that it can be shared between pages
Page = withSpace(makeRootSpace)(Page);
export default Page;
When you page component is wrapped by withSpace
, it auto-creates the root space when getInitialProps
is called by Next.js along with a sub-space dedicated to the page component (with the same name as the component). The page's space is passed down to the page's component as a prop called space
. On the client side it also takes care of using same root space every time, whereas on server a new root space is created for each request, which is then set on the client.
The withSpace
function accepts a makeRootSpace
function as first argument. The makeRootSpace
function will receive initial state as the first argument and should return a new instance Space
each time when called, no memoization needed here, it is automatically handled by the withSpace
wrapper. Pass the desired initial state for the page's space as the second parameter when calling withSpace
.
withSpace
also optionally accepts an object. In this case only 1 parameter is passed which can contain the following
configuration properties:
createRootSpace
(required, function) : themakeRootSpace
function as described aboverootSpaceKey
(optional, string) : the key used onwindow
to persist the root space on the clientdebug
(optional, boolean) : enable debug logging
When makeRootSpace
is invoked it is also provided a configuration object as the second parameter, which includes:
isServer
(boolean):true
if called while on the server rather than the clientreq
(Request): Thenext.js
getInitialProps
contextreq
parameterquery
(object): Thenext.js
getInitialProps
contextquery
parameter
The object also includes all configuration as passed to withSpace
if called with an object of configuration properties.
Use withSpace
to wrap only top level pages! All other components should keep using subSpace(…)
Although it is possible to create server or client specific logic in both createRootSpace
function and getInitialProps
it is highly recommended to not have different behaviour. This may cause errors and checksum mismatches which in turn will ruin the whole purpose of server rendering.
I don't recommend to using withSpace
in both top level pages and _document.js
files, Next.JS does not provide a reliable way to determine the sequence when components will be rendered. So per Next.JS recommendation it is better to have just data-agnostic things in _document
and wrap top level pages with another HOC that will use withSpace
.
function getInitialProps({space, isServer, pathname, query}) {
const startingDataPromise = fetch(…).then(res => res.json());
// once the data arrives we can resume and render the app
return startingDataPromise.then((startingData) => {
space.setState({ userId: startingData.userId });
return {custom: 'custom'};
});
}