State management can go from trivial to complex quickly as your code develops.
The State class offered by Palette is powerful, flexible, and offers
advanced deep reactivity observation.
The Component class deeply integrates with the State system, re-rendering
whenever a new state is computed. You can use the built-in state in components,
or create standalone State instances for shared state or stores.
The State class is generic, taking a type parameter representing the shape of
the stateful data. State must be an object.
interface AppStateShape {
view: "home" | "profile";
username: string;
lastInteraction: Date;
settings: {
invisible: boolean;
tags: string[];
}
}
const appState = new State<AppStateShape>({
view: "home",
username: "jason-bourne",
lastInteraction: new Date(),
settings: {
invisible: true,
tags: ["not-tom-cruise"],
}
});
You can add listeners to state instances which will run whenever state changes:
appState.addListener((data) => {
console.log(`Jesus Christ, that's ${data.username}`);
})
Or you can fetch data manually:
appState.get("view") // => "home"
appState.current.username // => "jason-bourne"
But what good is state if we can't change it up?
There's a bunch of ways to change state depending on what you need. Pick yer poison.
// A simple set of a top level property
appState.set("view", "profile");
// Update multiple things at once
appState.patch({
view: "home",
lastInteraction: new Date(),
});
// Functional mutation
appState.mutate((state) => {
// You can safely modify `state` here, it's a deep clone
state.view = "home";
return state;
});
// Transaction-style mutation
appState.transaction((state) => {
// `state` is a cloned, full State instance
state.set("view", "home");
state.set("lastInteraction", new Date());
});
// Live accessor with deep reactivity
state.live.view = "profile";
// Nested updates supported
state.live.settings.invisible = false;
// Array mutators are also supported
state.live.settings.tags.push("another-one");
At any time, you can wipe away the whole state and replace it, forcing all listeners to receive the new state data.
appState.replace({
view: "home",
username: "tom-cruise",
lastInteraction: new Date(),
settings: {
invisible: false,
tags: ["is-tom-cruise"],
},
})