Awesome
Effector Next
Note: we recommend using
@effector/next
package.
A HOCs that brings Effector and Next.js together
Installation
npm install effector-next
or yarn
yarn add effector-next
effector-next requires effector
, effector-react
to be installed
effector/babel-plugin is necessary if you do not want to manually name the units
Settings
-
To load the initial state on the server, you must attach
<details> <summary>pages/_document.jsx</summary>withFork
wrapper to your_document
component
</details>import Document from "next/document"; import { withFork } from "effector-next"; const enhance = withFork({ debug: false }); export default enhance(Document);
-
To get the initial state on the client and drop it into the application, you must attach
<details> <summary>pages/_app.jsx</summary>withHydrate
wrapper to your_app
component
</details>import { withHydrate } from "effector-next"; import App from "next/app"; const enhance = withHydrate(); export default enhance(App);
-
To bind events/stores on the server to the scope, add aliases from
<details> <summary>next.config.js</summary>effector-react
toeffector-react/ssr
innext.config.js
</details>const { withEffectorReactAliases } = require("effector-next/tools"); const enhance = withEffectorReactAliases(); module.exports = enhance({});
-
Replace imports from
"effector"
to"effector-next"
- import { createEvent, forward } from "effector" + import { createEvent, forward } from "effector-next"
-
Connect the
<details> <summary>.babelrc</summary>effector/babel-plugin
{ "presets": ["next/babel"], "plugins": ["effector/babel-plugin"] }
If you are using
effector
version > 21.3.0, you also need to configure the babel plugin:
</details>{ "presets": ["next/babel"], "plugins": ["effector/babel-plugin", { "importName": ["effector-next"] }] }
-
Configure what event will be triggered when the page is requested from the server using
<details> <summary>pages/index.js</summary>withStart
</details>import React from "react"; import { withStart } from "effector-next"; import { useStore } from "effector-react"; import { pageLoaded } from "../model"; const enhance = withStart(pageLoaded); function HomePage() { return ( <div> <h1>Hello World</h1> </div> ); } export default enhance(HomePage);
Example
-
Declare our model
<details> <summary>models/index.js</summary>
</details>import { forward, createEvent, createStore, createEffect } from "effector-next"; export const pageLoaded = createEvent(); export const buttonClicked = createEvent(); const effect = createEffect({ handler(name) { return Promise.resolve({ name }); }, }); export const $data = createStore(null); $data.on(effect.done, (_, { result }) => result); forward({ from: pageLoaded.map(() => "nameFromPageLoaded"), to: effect, }); forward({ from: buttonClicked.map(() => "nameFromButtonClicked"), to: effect, });
-
Connect the page to the store (all units must be wrapped in hooks - this is necessary in order to associate units with scope on the server)
<details> <summary>pages/index.jsx</summary>
</details>import React from "react"; import { useStore, useEvent } from "effector-react"; import { $data, buttonClicked } from "../models"; export default function HomePage() { const data = useStore($data); const handleClick = useEvent(buttonClicked); return ( <div> <h1>HomePage</h1> <h2>Store state: {JSON.stringify({ data })}</h2> <button onClick={handleClick}>click to change store state</button> </div> ); }
-
Bind an event that will be called on the server when the page is requested
<details> <summary>pages/index.jsx</summary>
</details>import React from "react"; import { useStore, useEvent } from "effector-react"; +import { withStart } from "effector-next"; -import { $data, buttonClicked } from "../models"; +import { $data, pageLoaded, buttonClicked } from "../models"; +const enhance = withStart(pageLoaded); -export default function HomePage() { +function HomePage() { const data = useStore($data); const handleClick = useEvent(buttonClicked); return ( <div> <h1>HomePage</h1> <h2>Store state: {JSON.stringify({ data })}</h2> <button onClick={handleClick}>click to change store state</button> </div> ); } +export default enhance(HomePage);
Configuration
The withFork
accepts a config object as a parameter:
debug
(optional, boolean) : enable debug loggingserializeIgnore
(optional, array) : stores whose values should not be sent to the client after serialization
Server payload
When the unit passed to withStart
is called, the object will be passed as a payload:
req
: incoming requestres
: serever responsecookies
: parsed cookiespathname
: path section ofURL
query
: query string section ofURL
parsed as an object.
Release process
- Check out the draft release.
- All PRs should have correct labels and useful titles. You can review available labels here.
- Update labels for PRs and titles, next manually run the release drafter action to regenerate the draft release.
- Review the new version and press "Publish"
- If required check "Create discussion for this release"