FragmentFragment

Create a Store

Centralized reactive state shared across any number of Handles.

A Store is a named, reactive data container. Any Handle that reads from a Store via useStore is automatically subscribed and will re-render whenever the store's data changes.

Fragment's store pattern is inspired by Zustand.


Define a Store

Each Store lives in its own ModuleScript inside your Stores/ folder. The builder function receives set and get, and must return the initial state table including any methods you want to expose.

Stores/PlayerDataStore.luau
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Fragment = require(ReplicatedStorage.Fragment)

return Fragment.createStore("PlayerData", function(set, get)
    return {
        coins = 0,
        level = 1,

        setCoins = function(amount: number)
            set({ coins = amount })
        end,

        addCoins = function(amount: number)
            set({ coins = get().coins + amount })
        end,

        getData = function()
            return get()
        end,
    }
end)

set(partial) does a shallow merge into the store and re-renders all subscribed Handles. get() returns the full live store table.

Use the structured loader

When using Fragment.load({ Stores = ..., Handles = ... }), Stores are required before Handles automatically — no manual require needed.

FragmentLoad.client.luau
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Fragment = require(ReplicatedStorage.Fragment)

Fragment.load({
    Stores  = script.Parent.Stores,  -- required first --
    Handles = script.Parent.Handles,
})

Connect a Store to a Handle

Use Fragment.useStore inside a renderer to read from the store and subscribe the Handle. The Handle re-renders automatically whenever set is called.

Handles/HUDHandle.luau
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Fragment = require(ReplicatedStorage.Fragment)

local Handle = Fragment.newHandle("HUD", { "HUD", "StatsFrame" })

return Handle(function(element: Frame)
    local store = Fragment.useStore("PlayerData") 
    local data  = store.getData()
    if not data then return end

    element.Coins.Text = `🪙 {data.coins}`
    element.Level.Text = `Lv. {data.level}`
end)

Subscription is automatic

Calling useStore inside a renderer subscribes the Handle. You do not need to manually unsubscribe — Fragment manages this for you.

Stores are also available inside Component renderers via the handle argument:

Components/CoinDisplay.luau
return Component(function(element, props, handle)
    local store = Fragment.useStore("PlayerData") 
    element.Text = `🪙 {store.getData().coins}`
end)

Mutating store data from a signal

You can call store methods from anywhere — inside Connect callbacks, from other Handles, or from a service.

Handles/HUDHandle.luau
return Handle(function(element: Frame)
    local store = Fragment.useStore("PlayerData")

    Handle.Connect("AddCoins", element.DebugBtn.Activated, function()
        store.addCoins(100) -- triggers re-render on all subscribed Handles --
    end)
end)

Integrating with external data sources

A common pattern is to populate the store when external data arrives — for example from ReplicaService or a remote event.

FragmentLoad.client.luau
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Fragment = require(ReplicatedStorage.Fragment)

Fragment.load({
    Stores  = script.Parent.Stores,
    Handles = script.Parent.Handles,
})

local store = Fragment.useStore("PlayerData")
ReplicaService.ReplicaOfClassCreated("PlayerData", function(replica)
    store.setCoins(replica.Data.Coins) 

    replica:ListenToChange({ "Coins" }, function(newValue)
        store.setCoins(newValue) 
    end)
end)

On this page