Compare commits
1 Commits
kcl-76
...
franknoiro
Author | SHA1 | Date | |
---|---|---|---|
7ca51be5bc |
@ -18,7 +18,7 @@ import { markOnce } from '@src/lib/performance'
|
|||||||
import { loadAndValidateSettings } from '@src/lib/settings/settingsUtils'
|
import { loadAndValidateSettings } from '@src/lib/settings/settingsUtils'
|
||||||
import { trap } from '@src/lib/trap'
|
import { trap } from '@src/lib/trap'
|
||||||
import type { IndexLoaderData } from '@src/lib/types'
|
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({})
|
export const RouteProviderContext = createContext({})
|
||||||
|
|
||||||
@ -34,6 +34,38 @@ export function RouteProvider({ children }: { children: ReactNode }) {
|
|||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const settings = useSettings()
|
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(() => {
|
useEffect(() => {
|
||||||
// On initialization, the react-router-dom does not send a 'loading' state event.
|
// On initialization, the react-router-dom does not send a 'loading' state event.
|
||||||
// it sends an idle event first.
|
// it sends an idle event first.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { useSelector } from '@xstate/react'
|
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 { createSettings } from '@src/lib/settings/initialSettings'
|
||||||
import { authMachine } from '@src/machines/authMachine'
|
import { authMachine } from '@src/machines/authMachine'
|
||||||
@ -9,13 +9,15 @@ import {
|
|||||||
engineStreamMachine,
|
engineStreamMachine,
|
||||||
} from '@src/machines/engineStreamMachine'
|
} from '@src/machines/engineStreamMachine'
|
||||||
import { ACTOR_IDS } from '@src/machines/machineConstants'
|
import { ACTOR_IDS } from '@src/machines/machineConstants'
|
||||||
|
import { routerMachine } from '@src/machines/routerMachine'
|
||||||
import { settingsMachine } from '@src/machines/settingsMachine'
|
import { settingsMachine } from '@src/machines/settingsMachine'
|
||||||
|
|
||||||
const { AUTH, SETTINGS, ENGINE_STREAM } = ACTOR_IDS
|
const { AUTH, SETTINGS, ENGINE_STREAM, ROUTER } = ACTOR_IDS
|
||||||
const appMachineActors = {
|
const appMachineActors = {
|
||||||
[AUTH]: authMachine,
|
[AUTH]: authMachine,
|
||||||
[SETTINGS]: settingsMachine,
|
[SETTINGS]: settingsMachine,
|
||||||
[ENGINE_STREAM]: engineStreamMachine,
|
[ENGINE_STREAM]: engineStreamMachine,
|
||||||
|
[ROUTER]: routerMachine,
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
const appMachine = setup({
|
const appMachine = setup({
|
||||||
@ -23,6 +25,12 @@ const appMachine = setup({
|
|||||||
children: {
|
children: {
|
||||||
auth: typeof AUTH
|
auth: typeof AUTH
|
||||||
settings: typeof SETTINGS
|
settings: typeof SETTINGS
|
||||||
|
engine_stream: typeof ENGINE_STREAM
|
||||||
|
router?: typeof ROUTER
|
||||||
|
}
|
||||||
|
events: {
|
||||||
|
type: 'event:router_set_up'
|
||||||
|
data: InputFrom<typeof routerMachine>
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actors: appMachineActors,
|
actors: appMachineActors,
|
||||||
@ -41,9 +49,30 @@ const appMachine = setup({
|
|||||||
input: engineStreamContextCreate(),
|
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)
|
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
|
* 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
|
* the lifetime of {appActor}, but would not work if it were invoked
|
||||||
|
@ -2,4 +2,5 @@ export const ACTOR_IDS = {
|
|||||||
AUTH: 'auth',
|
AUTH: 'auth',
|
||||||
SETTINGS: 'settings',
|
SETTINGS: 'settings',
|
||||||
ENGINE_STREAM: 'engine_stream',
|
ENGINE_STREAM: 'engine_stream',
|
||||||
|
ROUTER: 'router',
|
||||||
} as const
|
} 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