# State Management with xstate - Objective: - it needs to be run on both platform (RN and Web) - Questions: - Network - - App State / Global State - We need to have a grasp of how the application actually works - Currently, we don't have a model to know what application are doing - We already have pattern to make sure this is the case. But the debugging experience is not as good as it should (is it necessary?) - Problems of this current appoach, we need lot of effort to know exactly what is being consumed by our app - UI State - - Do we need to use the same tools to manage state and network state? - In our case, we already use [React Query]() - For global state, we already use [Zustand]() ## Current Approach - Pros - We have already dedicated tools to do very specific job. And they are doing really well - [React Query]() for network state - [Zustand]() for global state - Much more simpler to use - Functionality is a big plus for specific tools [React Query]() - Refetch Functionality - Cache - Window Focus (Refeching) - `let {isLoading, error, data} = useQuery(key, promise)` - Developer Experience is great - Network API is a big plus - Zustand is improvement over React Context - Much simpler to use - It's already baked with selector. No rerender for non-related component - Cons - [React Query]() SSR Story is not good - Singleton object for data - user -> asking for page -> ssr -> put the data to react query -> check the stale status -> it's stale -> giving empty object -> client think that the data is stale -> refetch - Client not doing SSR - SSR Failed - SSR is not sharable - ```ts import {hydrate} from 'react-query'; // hydrate :: 'data => Omit<data, "updedDate">; async function getServerSideProps() { let data = await getData(); return {props: { data: hydrate(data); }} } ``` - in turns that the `etag` generated by the server is always different. If we have a case like the client need to validate the data, it always failed because etag always different from the last time. - Zustand SSR [link](https://github.com/pmndrs/zustand/issues/182) - ## Model ```ts let userMachine = createMachine({ context: { user: null }, initial: 'idle', states: { idle: { invoke: { src: 'fetchUserData', onSuccess: 'data', onError: 'error' } on: { FETCH: {target: 'loading'} } }, loading: { on: { SUCCESS: {target: 'data'} } }, data: { on: { } } } }, { services: { fetchUserData: () => { } } }) ``` ```ts function UserProfileRoute(props) { let user = useActor(userMachine(initial: )).withContext({ user: props.user }) } async function getServersideProps() { let user = await fetchUserData(); return { props: { user } } } ``` ```ts // const: visual editor? let userMachine = (initial, user) => createMachine({ context: { user: null }, initial: initial, states: { idle: { tag: 'watiting' invoke: { src: 'fetchUserData', onSuccess: 'data', onError: 'error' } on: { FETCH: [ {cond: (ctxt) => ctx.user ? true: false, target: 'data'} ] }, loading: { tag: 'loading', on: { SUCCESS: {target: 'data'} } }, data: { on: { } } } }, { services: { fetchUserData: () => { } } }) // abstract this away from user state.tags("loading") => <Loading Component /> state.context.user && state.tags("data") => <Data /> // let data = ``` ### Explore - Xstate Modelnya gimana? - context - zustand - redux - Pattern - File and Folder Structure - ## SSR - context? - ssr story? - boilerplate? - network? ## References - [xstate with redux](https://github.com/mattpocock/redux-xstate-poc) - [xstate context](https://github.com/coder/coder/tree/main/site/src/xServices) - [RFC](https://github.com/statelyai/rfcs/blob/davidkpiano/0002-system-receptionist/text/0000-system-receptionist.md) -