# 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)
-