The State of
State Management
Thupi Ceylons
Software Engineer at Danske Bank
But why?
Why am i doing this talk...
Living life as you do...

"There's a new state management system!" - colleague

...Migrating all my hobby projects

So i would like to
Share my learnings with you
So lets get the basics out of the way
What is state?
const Component = () => {
const [count, setCount] = useState(0);
return (
<div>
{count}
<button onClick={() => setCount(count => ++count)}>+</button>
<button onClick={() => setCount(count => --count)}>-</button>
</div>
);
}
React Component State
https://jsfiddle.net/3qLrcg2e/
const StateContext = React.createContext();
const Root = () => {
const state = React.useState(0);
return (
<StateContext.Provider value={state}>
<Component />
</StateContext.Provider>
);
}
const Component = () => {
const [count, setCount] = React.useContext(StateContext);
return (
<div>
{count}
<button onClick={() => setCount(count => ++count)}>+</button>
<button onClick={() => setCount(count => --count)}>-</button>
</div>
);
}
ReactDOM.render(<Root />, document.querySelector("#app"))
React Context
https://jsfiddle.net/3qLrcg2e/1/
The mental model of React
view = f(state)
Okay thats cool...
Why do we need anything else?
State Management
Performance
Flexibility
Features
DX
State Management
Performance
Flexibility
Features
DX
Transient updates
Immutability/Reactivity
Selectors
Performance
Flexibility
Features
DX
Internal/external
Composable
derived or computed state
Performance
Flexibility
Features
DX
Runtime type checking
Timetravel
Patches
Performance
Flexibility
Features
DX
Debugging tools
Infered typechecking
Boilerplate
State Management
Performance
Flexibility
Features
DX
Lets take a look at a few options
A few state managements systems
Redux
Is based on Immutability
Is managed internally
Opinionated structure
Centralized state
Mobx
Is based on observability
Is managed externally
Flexible structure
Distributed state
Redux
Mobx
// Actions
export const add = () => ({
type: 'ADD',
})
export const subtract = () => ({
type: 'SUBTRACT',
})
// Reducers
const reducer = (state = { count: 0 }, action) => {
switch (action.type) {
case 'ADD':
return { ...state, count: state.count + 1 }
case 'SUBTRACT':
return { ...state, count: state.count - 1 }
default:
return state
}
}
// Selectors
const getCount = (state) => state.count;
const Component = ({count, add, subtract}) => {
return (
<div>
<h2>{count}</h2>
<button onClick={add}>
+
</button>
<button onClick={subtract}>
-
</button>
</div>
)
)
const mapStateToProps = state => ({
count: getCount(state)
})
const mapDispatchToProps = dispatch => ({
add: () => dispatch(actions.add()),
subtract: () => dispatch(actions.subtract())
})
const ConnectedComponent = connect(
mapStateToProps,
mapDispatchToProps
)(Component)
// const store = createStore(reducer);
// render(
// <Provider store={store}>
// <App />
// </Provider>,
// document.getElementById('root')
// )
const appState = observable({
count: 0,
subtract: action(function() {
appState.count -= 1;
}),
add: action(function () {
appState.count += 1;
})
})
const Component = observer(() => {
return (
<div>
<h2>{appState.count}</h2>
<button onClick={appState.add}>
+
</button>
<button onClick={appState.subtract}>
-
</button>
</div>
)
})But these are the OG state managers...
What about the new kids in the block
Jotai
Is based on Immutability
Is managed internally
Opinionated structure
Centralized state
Zustand
Is based on Immutability
Is managed externally
Flexible structure
Distributed state
Jotai
Zustand
const countAtom = atom(0);
const addCountAtom = atom(null, (_get, set) => {
set(countAtom, (c) => c + 1);
});
const subtractCountAtom = atom(null, (_get, set) => {
set(countAtom, (c) => c - 1);
});
const Component = () => {
const [count] = useAtom(countAtom);
const [, add] = useAtom(addCountAtom);
const [, subtract] = useAtom(subtractCountAtom);
return (
<div>
{count}
<button onClick={add}>
+
</button>
<button onClick={subtract}>
-
</button>
</div>
);
};const useCountStore = create((set) => ({
count: 0,
add: () => set((prev) => ({ count: prev.count + 1 })),
subtract: () => set((prev) => ({ count: prev.count - 1 }))
}));
const Component = () => {
const state = useStore();
return (
<div>
{state.count}
<button onClick={state.add}>
+
</button>
<button onClick={state.subtract}>
-
</button>
</div>
);
};But which state manager did i pick?
Well, lets try to compare both
Zustand
Is based on Immutability
Is managed externally
Flexible structure
Distributed state
Valtio
Is based on Reactivity
Is managed externally
Flexible structure
Distributed state
(current)
(new)
const useCountStore = create((set) => ({
count: 0,
add: () => set((prev) => ({ count: prev.count + 1 })),
subtract: () => set((prev) => ({ count: prev.count - 1 }))
}));
const Component = () => {
const state = useStore();
return (
<div>
{state.count}
<button onClick={state.add}>
+
</button>
<button onClick={state.subtract}>
-
</button>
</div>
);
};const countState = proxy({
count: 0,
});
const add = () => { countState.count += 1 };
const subtract = () => { countState.count -= 1 };
const Component = () => {
const state = useSnapshot(countState);
return (
<div>
{state.count}
<button onClick={add}>
+
</button>
<button onClick={subtract}>
-
</button>
</div>
);
};Zustand
Valtio
(current)
(new)
Zustand
Immutability stays close to react
Works as expected.
Manual render optimization
Tends to use less memory
Less compatible with built-in react features
Valtio
Proxies are unusual in react.
Works magically
Automatic render optimization
Tends to use more memory
More compatible with built-in react features
(current)
(new)
Thanks for great state managers
Daishi Kato @ dai-shi
If someone comes from redux or likes react's natural immutable updates, zustand would fit well.
If someone is from vue/svelte/mobx, or new to JS and/or react, valtio's mutable model would fit well.
zustand is a very thin library and never behaves unexpectedly. valtio comes with proxy magic.
Oh my...
Did we cover it all?
Immer
Recoil
State Machines
Server cache state
Form state
unstated
Server side rendering support
Server Cache State
Packages: React-Query, Apollo
Purpose: Maintain server state
Finite State Machines
Packages: Xstate
Purpose: Maintain the relations between states.
Specialised
State Managements
Solutions
Useful links for when you are figuring out...
How to pick a state manager
- All in one guide:
- Video: https://www.youtube.com/watch?v=u_o09PD_qAs
- Article: https://leerob.io/blog/react-state-management
- Does it support concurrent rendering?
- https://github.com/dai-shi/will-this-react-global-state-work-in-concurrent-rendering
- https://github.com/dai-shi/will-this-react-global-state-work-in-concurrent-rendering
- Basic comparison between state managers
- https://github.com/dai-shi/lets-compare-global-state-with-react-hooks
The State of State Management
By thupi
The State of State Management
- 171