Crate
A simple to use, scalable state container built for the roblox-ts ecosystem.
new Crate<User>({
name: "Neohertz",
character: {
health: 0,
walkSpeed: 0,
}
stats: {
kills: 0,
deaths: 0,
}
})
Please note that Crate.ts is still in early development. The API is not final, and is subject to breaking changes. You may encounter bugs! Use at your own risk.
Features
💫 Magical Mutation
Crate's update method allows you to update deeply nested partial tables easily.
// Kill the player and increment their deaths.
user.update({
character: {
health: 0 // Set health to 0
},
stats: {
deaths: (v) => v + 1 // Increment Deaths
}
})
⚡️ Lightning Fast Access
Using a selector pattern inspired by reflex, accessing data from crates is fast and easy as pie.
const userName = user.getState(
(state) => state.name,
)
print(userName) // "ztrehoeN"
👀 Smart Listeners
Use crate's onUpdate()
method to listen to specific parts of your store.
// Listen to state updates to a specific member (deaths)
user.onUpdate(
(state) => state.stats.deaths,
(deaths) => print(deaths) // 1
)
Crates also provide a listener that receives an update describing the changes made between state updates. This allows you to easily replicate the state, validate data, and more!
user.useDiff((diff) => {
print(diff) // { name: "Neohertz" }
})
user.update({
name: (v) => v.reverse(), // included, state does change.
stats: {
kills: 0, // doesn't get included since it's equal.
}
})
🪄 Side Effects
Mutate incoming state updates with middleware.
// Ensure the player's health is never less than 0.
user.useMiddleware("character", (oldValue, newValue) => {
const { health, walkSpeed } = newValue;
return {
health: math.clamp(health, 0, math.huge),
walkSpeed,
}
})
// Deal a ridiculous amount of damage to the player.
user.update({
character: { health: (hp) => hp - 10000 }
})
// Retrieve final health value.
const hp = user.getState((s) => s.character.health)
print(hp) // 0 - was clamped by middleware.
⚛️ React Integration
Using the optional @rbxts/react-crate (opens in a new tab) package, you can easily listen and memoize state updates in react components.
const crate = new Crate<ClientState>({
clicks: 0,
});
export function ButtonComponent() {
const clicks = useCrate(crate, state => state.clicks);
return (
<textbutton
Event={{
MouseButton1Click: () => {
crate.update({ clicks: v => v + 1 });
},
}}
Size={UDim2.fromOffset(200, 50)}
Text={`Clicks: ${clicks}`}
/>
);
}
Think you're ready to give crate a test drive? Get Started →