Updating State
Davstack Store provides two main methods for updating state: set
and assign
. Both methods use Immer under the hood, allowing you to update state immutably.
Example
import { store } from '@davstack/store';
const userStore = store()
.state({
name: 'John',
age: 25,
address: {
street: '123 Main St',
city: 'Anytown',
},
})
.actions((store) => ({
happyBirthday() {
store.age.set(store.age.get() + 1);
},
}));
function AddressForm() {
const userAddress = userStore.address.use();
return (
<form>
<input
value={userAddress.street}
onChange={(e) => userStore.address.street.set(e.target.value)}
/>
<input
value={userAddress.city}
onChange={(e) => userStore.address.city.set(e.target.value)}
/>
</form>
);
}
Best Practices
- It's generally recommended to enapsulate state updates in actions, and avoid directly mutating state properties outside of actions. This helps to keep your codebase clean and maintainable.
- Use the
set
method to update a single state property, andassign
to update multiple properties at once.
The set
Method
Use set
to update the value of a state property.
import { store } from '@davstack/store';
const countStore = store(0);
countStore.set(5);
The set method can also be used to update nested state properties:
const userStore = store({
name: 'John',
age: 25,
address: {
street: '123 Main St',
city: 'Anytown',
},
});
userStore.address.city.set('Newtown');
The assign
Method
The assign
method is similar to set
but is specifically designed for updating multiple properties of an object at once. It uses Object.assign
under the hood.
const userStore = store({
name: 'John',
age: 25,
address: {
street: '123 Main St',
city: 'Anytown',
},
});
userStore.assign({
name: 'Jane',
age: 30,
});
When using assign
, only the specified properties will be updated. Other
properties will remain unchanged.
Updating Nested State with assign
You can also use assign
to update multiple nested state properties:
userStore.address.assign({
street: '456 Elm St',
city: 'Newtown',
});
Note: the assign
method only exists on object data type
Set with callback functions
The set
function can accept a value or a callback function
Set value example: counterStore.set(5)
Set callback function example: counterStore.set(()=>{...})
Datatype differences summary
The type of callback function changes depending on the state datatype.
Objects/Arrays: directly modify the draft, don't return anything Primitives: get previous value, return new value
(The types fully reflect which type of callback is required and therefore your IDE will guide you.)
Object / Array set callback details
Calling .set
on an object/array uses immer under the hook, allowing you to mutate a draft copy of the state while maininaining immutability.
const userStore = store({ name: 'John', age: 20 });
// draft object uses immer
userStore.set((draft) => {
draft.name = 'Jane';
draft.age = 30;
});
const todosStore = store([
{ id: 1, text: 'write docs' },
{ id: 2, text: 'sleep' },
]);
todosStore.set((draft) => {
draft.push('another task');
});
todosStore.set((draft) => {
const firstTodo = draft[0];
firstTodo.text = 'new text';
});
Primitives set callback details
Calling set
on other data types behaves slightly differently.
You are given the previous value of the property and you must return the new value from the callback.
userStore.age.set((prevAge) => prevAge + 1);
Additional notes:
-
Non-draftable values (e.g., MediaRecorder or window) will be considered as primitive values
-
Since
@davstack/store 1.3.0
root level array stores are fully supported