|
1 | | -import { useEffect, useReducer, Dispatch } from 'react'; |
| 1 | +import { useEffect, useReducer, Dispatch, useRef } from 'react'; |
2 | 2 |
|
3 | 3 | type Transition = |
4 | 4 | | string |
@@ -84,19 +84,28 @@ const getReducer = < |
84 | 84 | }; |
85 | 85 | }; |
86 | 86 |
|
| 87 | +const useConstant = <T,>(init: () => T) => { |
| 88 | + const ref = useRef<T | null>(null); |
| 89 | + |
| 90 | + if (ref.current === null) { |
| 91 | + ref.current = init(); |
| 92 | + } |
| 93 | + return ref.current; |
| 94 | +}; |
| 95 | + |
87 | 96 | export default function useStateMachine<Context extends Record<PropertyKey, any>>(context?: Context) { |
88 | 97 | return function useStateMachineWithContext<Config extends MachineConfig<Context>>(config: Config) { |
89 | 98 | type IndexableState = keyof typeof config.states; |
90 | 99 | type State = keyof Config['states']; |
91 | 100 | type Event = KeysOfTransition<TransitionEvent<Config['states']>>; |
92 | 101 |
|
93 | | - const initialState = { |
| 102 | + const initialState = useConstant(() => ({ |
94 | 103 | value: config.initial as State, |
95 | 104 | context: context ?? ({} as Context), |
96 | 105 | nextEvents: Object.keys(config.states[config.initial].on ?? []) as Event[], |
97 | | - }; |
| 106 | + })); |
98 | 107 |
|
99 | | - const reducer = getReducer<Context, Config, State, Event>(config); |
| 108 | + const reducer = useConstant(() => getReducer<Context, Config, State, Event>(config)); |
100 | 109 |
|
101 | 110 | const [machine, send] = useReducer(reducer, initialState); |
102 | 111 |
|
|
0 commit comments