Xstate and Next.js #1633
-
|
Hi! First of all, great work on this amazing library. It's absolutely fantastic. I'm new to it and I've been using it to model the step by step process of a purchase flow using Next.js with a top level machine. Each step in the flow is both a machine state and a Next.js page and when a page changes, I'm triggering a state change from within a listener listening to the Next.js routing events. What's the best approach do I make this top level machine available for nested components? Right now I've setup the machine in Thank you! |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 10 replies
-
|
You can freely put a machine into React’s context or you can even share it as a singleton in your app. Possibilities are endless 😉 Other than that it’s hard to advise something more concrete because I’m not fully sure how do u want to utilize this machine in your app. An illustrating runnable example would be appreciated. |
Beta Was this translation helpful? Give feedback.
-
|
This is how I do it with hooks and contexts: I have a separate
This is how they look like:
id: home
type: parallel
context:
states:
theme:
id: theme
initial: default
states:
default:
meta:
container:
sx:
backgroundColor: combinations.retro.backgrounds.100
layout:
id: layout
initial: default
states:
default:
meta:
container:
sx:
width: 100%
height: 100%
content:
id: content
initial: default
states:
default:
meta:
import * as X from "xstate"
export default {
actions: {},
activities: {},
services: {},
guards: {}
}
import React from "react"
import * as X from "xstate"
import states from "./states.yaml"
import options from "./options.js"
import { useMachine } from "@xstate/react"
import merge from "deepmerge"
export const machine = X.createMachine(states, options)
export const service = X.interpret(machine)
export const create = () => {
const [state, send, service] = useMachine(machine, { devTools: true })
const theme = state.meta[`home.theme.${state.value.theme}`]
const layout = state.meta[`home.layout.${state.value.layout}`]
const content = state.meta[`home.content.${state.value.content}`]
const styles = merge(theme, layout)
return { styles, content }
}
export const Context = React.createContext()
export const Consumer = Context.Consumer
export const Provider = p => <Context.Provider value={create()} {...p} />
export const use = () => React.useContext(Context)
export default { machine, service, Context, Provider, Consumer, use, create }In above file export const create = () => {
const [state, send, service] = useMachine(machine, { devTools: true })
const theme = state.meta[`home.theme.${state.value.theme}`]
const layout = state.meta[`home.layout.${state.value.layout}`]
const content = state.meta[`home.content.${state.value.content}`]
const styles = merge(theme, layout)
const toggle = {
theme: () => send("toggle.theme"),
layout: () => send("toggle.layout")
}
return { styles, content, toggle }
}This is the part in export const Context = React.createContext()
export const Consumer = Context.Consumer
export const Provider = p => <Context.Provider value={create()} {...p} />
export const use = () => React.useContext(Context)
export default { machine, service, Context, Provider, Consumer, use, create }If you want to share it across entire app, you'll first have to add the Provider of this state machine in import React from "react"
import Home from "@/systems/universe/home"
import theme from "@/settings/theme"
import { ThemeProvider as Theme } from "theme-ui"
import "@/settings/theme/global.css"
export const Application = props => {
const { Component, pageProps } = props
return (
<Theme theme={theme}>
<Home.Provider>
<Component {...pageProps} />
</Home.Provider>
</Theme>
)
}
export default ApplicationComponent which uses the shared instance of a running machine looks something like this: import React from "react"
import System from "@/systems/universe/home"
import { Box } from "theme-ui"
const Home = () => {
const home = System.use()
const { styles, content } = home
return <Box {...styles.container}></Box>
}
export default HomeComponent which uses the new instance of a running machine across different react component looks something like this: import React from "react"
import System from "@/systems/universe/home"
import { Box } from "theme-ui"
const Home = () => {
const home = System.create()
const { styles, content } = home
return <Box {...styles.container}></Box>
}
export default Home
|
Beta Was this translation helpful? Give feedback.
-
|
https://docs.pmnd.rs/jotai/integrations/xstate Jotai + XState might be an option. |
Beta Was this translation helpful? Give feedback.
This is how I do it with hooks and contexts:
I have a separate
systemsfolder where I keep all the machines and hooks and contexts related to it. For example, let's say I want to have a state machine to be used inside ofhomepage or forpages/index.js, Then I'll create a folder at this location:src/systems/universe/homeand this folder will contain 3 files:states.yaml- YAML representation of state machine.options.js- A file that simply exports an object with keysactions,activities,guardsandservices.index.js- contains variables to be exported so that this machine is usable across components (sharable, and independent services both).This is how they look like:
states.yaml- …