Compare commits
1 Commits
main
...
franknoiro
Author | SHA1 | Date | |
---|---|---|---|
7ca51be5bc |
@ -18,7 +18,7 @@ import { markOnce } from '@src/lib/performance'
|
||||
import { loadAndValidateSettings } from '@src/lib/settings/settingsUtils'
|
||||
import { trap } from '@src/lib/trap'
|
||||
import type { IndexLoaderData } from '@src/lib/types'
|
||||
import { settingsActor, useSettings } from '@src/machines/appMachine'
|
||||
import { appActor, settingsActor, useSettings } from '@src/machines/appMachine'
|
||||
|
||||
export const RouteProviderContext = createContext({})
|
||||
|
||||
@ -34,6 +34,38 @@ export function RouteProvider({ children }: { children: ReactNode }) {
|
||||
const location = useLocation()
|
||||
const settings = useSettings()
|
||||
|
||||
/**
|
||||
* Spawn a router machine that we can interact with outside of React,
|
||||
* but providing the react-router-dom methods and information we need.
|
||||
*/
|
||||
useEffect(() => {
|
||||
appActor.send({
|
||||
type: 'event:router_set_up',
|
||||
data: {
|
||||
location,
|
||||
navigation,
|
||||
navigate,
|
||||
},
|
||||
})
|
||||
}, [])
|
||||
/**
|
||||
* "Subscribe" to the location and navigation from react-router-dom
|
||||
* to keep the router actor up-to-date from here on out
|
||||
*/
|
||||
useEffect(() => {
|
||||
appActor.getSnapshot().children.router?.send({
|
||||
type: 'event:set_location',
|
||||
data: location,
|
||||
})
|
||||
}, [location])
|
||||
|
||||
useEffect(() => {
|
||||
appActor.getSnapshot().children.router?.send({
|
||||
type: 'event:set_navigation',
|
||||
data: navigation,
|
||||
})
|
||||
}, [navigation])
|
||||
|
||||
useEffect(() => {
|
||||
// On initialization, the react-router-dom does not send a 'loading' state event.
|
||||
// it sends an idle event first.
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { useSelector } from '@xstate/react'
|
||||
import { createActor, setup, spawnChild } from 'xstate'
|
||||
import { createActor, InputFrom, setup, spawnChild } from 'xstate'
|
||||
|
||||
import { createSettings } from '@src/lib/settings/initialSettings'
|
||||
import { authMachine } from '@src/machines/authMachine'
|
||||
@ -9,13 +9,15 @@ import {
|
||||
engineStreamMachine,
|
||||
} from '@src/machines/engineStreamMachine'
|
||||
import { ACTOR_IDS } from '@src/machines/machineConstants'
|
||||
import { routerMachine } from '@src/machines/routerMachine'
|
||||
import { settingsMachine } from '@src/machines/settingsMachine'
|
||||
|
||||
const { AUTH, SETTINGS, ENGINE_STREAM } = ACTOR_IDS
|
||||
const { AUTH, SETTINGS, ENGINE_STREAM, ROUTER } = ACTOR_IDS
|
||||
const appMachineActors = {
|
||||
[AUTH]: authMachine,
|
||||
[SETTINGS]: settingsMachine,
|
||||
[ENGINE_STREAM]: engineStreamMachine,
|
||||
[ROUTER]: routerMachine,
|
||||
} as const
|
||||
|
||||
const appMachine = setup({
|
||||
@ -23,6 +25,12 @@ const appMachine = setup({
|
||||
children: {
|
||||
auth: typeof AUTH
|
||||
settings: typeof SETTINGS
|
||||
engine_stream: typeof ENGINE_STREAM
|
||||
router?: typeof ROUTER
|
||||
}
|
||||
events: {
|
||||
type: 'event:router_set_up'
|
||||
data: InputFrom<typeof routerMachine>
|
||||
}
|
||||
},
|
||||
actors: appMachineActors,
|
||||
@ -41,9 +49,30 @@ const appMachine = setup({
|
||||
input: engineStreamContextCreate(),
|
||||
}),
|
||||
],
|
||||
on: {
|
||||
'event:router_set_up': {
|
||||
actions: spawnChild(ROUTER, {
|
||||
id: ROUTER,
|
||||
systemId: ROUTER,
|
||||
input: ({ event, context }) => {
|
||||
if (event.type !== 'event:router_set_up')
|
||||
return {
|
||||
location: {} as InputFrom<typeof routerMachine>['location'],
|
||||
navigation: {} as InputFrom<typeof routerMachine>['navigation'],
|
||||
navigate: (() => {}) as InputFrom<
|
||||
typeof routerMachine
|
||||
>['navigate'],
|
||||
}
|
||||
return event.data
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export const appActor = createActor(appMachine)
|
||||
// REMOVE THIS BEFORE MERGING
|
||||
window.appActor = appActor
|
||||
/**
|
||||
* GOTCHA: the type coercion of this actor works because it is spawned for
|
||||
* the lifetime of {appActor}, but would not work if it were invoked
|
||||
|
@ -2,4 +2,5 @@ export const ACTOR_IDS = {
|
||||
AUTH: 'auth',
|
||||
SETTINGS: 'settings',
|
||||
ENGINE_STREAM: 'engine_stream',
|
||||
ROUTER: 'router',
|
||||
} as const
|
||||
|
81
src/machines/routerMachine.ts
Normal file
81
src/machines/routerMachine.ts
Normal file
@ -0,0 +1,81 @@
|
||||
import { useLocation, useNavigate, useNavigation } from 'react-router-dom'
|
||||
import { assign, setup } from 'xstate'
|
||||
|
||||
export const routerMachine = setup({
|
||||
types: {} as {
|
||||
context: {
|
||||
location: ReturnType<typeof useLocation>
|
||||
navigation: ReturnType<typeof useNavigation>
|
||||
navigate: ReturnType<typeof useNavigate>
|
||||
}
|
||||
input: {
|
||||
location: ReturnType<typeof useLocation>
|
||||
navigation: ReturnType<typeof useNavigation>
|
||||
navigate: ReturnType<typeof useNavigate>
|
||||
}
|
||||
events:
|
||||
| {
|
||||
type: 'event:navigate'
|
||||
data: Parameters<ReturnType<typeof useNavigate>>
|
||||
}
|
||||
| { type: 'event:set_location'; data: ReturnType<typeof useLocation> }
|
||||
| { type: 'event:set_navigation'; data: ReturnType<typeof useNavigation> }
|
||||
},
|
||||
actions: {
|
||||
navigate: (
|
||||
_,
|
||||
params: {
|
||||
navigate: ReturnType<typeof useNavigate>
|
||||
args: Parameters<ReturnType<typeof useNavigate>>
|
||||
}
|
||||
) => {
|
||||
console.log("FRANK let's try and navigate", {
|
||||
params,
|
||||
})
|
||||
params.navigate(...params.args)
|
||||
},
|
||||
},
|
||||
}).createMachine({
|
||||
id: 'router',
|
||||
context: ({ input }) => ({
|
||||
...input,
|
||||
}),
|
||||
on: {
|
||||
'event:navigate': {
|
||||
actions: {
|
||||
type: 'navigate',
|
||||
params: ({ event, context }) => ({
|
||||
navigate: context.navigate,
|
||||
args: event.data,
|
||||
}),
|
||||
},
|
||||
},
|
||||
'event:set_location': {
|
||||
actions: assign({
|
||||
location: ({ event }) => event.data,
|
||||
}),
|
||||
},
|
||||
'event:set_navigation': {
|
||||
actions: assign({
|
||||
navigation: ({ event }) => event.data,
|
||||
}),
|
||||
},
|
||||
},
|
||||
// states: {
|
||||
// idle: {
|
||||
// on: {
|
||||
// 'event:navigate:start': {
|
||||
// target: 'navigating',
|
||||
// actions: ['navigate'],
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// navigating: {
|
||||
// on: {
|
||||
// 'event:navigate:end': {
|
||||
// target: 'idle',
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
})
|
Reference in New Issue
Block a user