@rbxts/shared-components-flamework
v2.7.3
Published
This package will allow you to create shared components that will synchronize between server and client. This package is reflex-based, so it is important to know how to work with it to understand how this package works.
Maintainers
Readme
š„ shared-components-flamework
A powerful library for creating synchronized server-client components in Roblox. This package simplifies state management and networking between server and client in components while maintaining type safety.
Features
š Automatic state synchronization between server and client
š·ļø Type-safe component definitions
š® Built-in networking with events and actions
šļø Support for decorators
š¦ Installation
npm install shared-components-flameworkš Getting Started
1ļøā£ Create Shared Component
// shared/components/counter.ts
// define state
interface State {
value: number;
}
@Component()
export class CounterComponent extends SharedComponent<State> {
protected state = { value: 0 }; // Initial state
}2ļøā£ Server Implementation
// server/components/counter.ts
@Component({ tag: "Counter" })
export class ServerCounterComponent extends CounterComponent implements OnStart {
public onStart() {
task.spawn(() => {
while (task.wait(3)) {
this.Increment();
}
});
}
@Action() // State modifier
private Increment() {
return {
...this.state,
value: this.state.value + 1,
};
}
}3ļøā£ Client Implementation
// client/components/counter.ts
@Component({
tag: "Counter",
})
export class ClientCounterComponent extends CounterComponent {
@Subscribe((state) => state.value)
private onIncrement(newValue: number) {
print(`new value: ${newValue}`);
}
}š Networking
With this package you can declare remote event, action inside the component, this will allow you to easily make interaction between server and client component
@Component()
export class SomeSharedComponent extends SharedComponent<{}> {
protected state = {};
protected remotes = {
ClientEvent: SharedComponentNetwork.event<ServerToClient, [value: number]>(),
ServerEvent: SharedComponentNetwork.event<ClientToServer, [value: number]>(),
Action: SharedComponentNetwork.action<[value: number], void>(),
};
}
// server
@Component({
tag: "SomeSharedComponent",
})
export class ServerComponent extends SomeSharedComponent implements OnStart {
public onStart() {
this.remotes.ServerEvent.Connect((player, amount) => {
print(`value = ${amount}, player: ${player}`);
});
this.remotes.Action.OnRequest((amount) => {
print(`Action: value = ${amount}`);
});
task.wait(5);
this.remotes.ClientEvent.Broadcast(1);
}
}
// client
@Component({
tag: "SomeSharedComponent",
})
export class ClientComponent extends SomeSharedComponent implements OnStart {
public onStart() {
this.remotes.ClientEvent.Connect((amount: number) => {
print(`value = ${amount}`);
});
this.remotes.ServerEvent.Fire(1);
this.remotes.Action(1);
}
}š API Reference
Core Components
SharedComponent<S, A, I>
The foundation class for all shared components
abstract class SharedComponent<
S = {}, // State type
A extends object = {}, // Attributes type
I extends Instance = Instance // Instance type
> extends BaseComponent<A & { __SERVER_ID?: string }, I>š·ļø Generics:
| Param | Description | Default |
|-------|-------------|---------|
| S | Component state type | any |
| A | Component attributes type | {} |
| I | Roblox Instance type | Instance |
š ļø Public Methods
GetState(): S
Returns current component state
const state = component.GetState();
print(`Current value: ${state.value}`);Dispatch(newState: S): S
Updates component state and triggers updates
component.Dispatch({
...component.GetState(),
value: 42
});Subscribe()
State change subscription methods
Overload 1 - Full state
Subscribe(listener: (state: S, prevState: S) => void): () => voidExample:
const unsubscribe = component.Subscribe((state, prevState) => {
print(`State changed from ${prevState.value} to ${state.value}`);
});Overload 2 - Selected value
Subscribe<T>(
selector: (state: S) => T,
listener: (value: T, prevValue: T) => void
): () => voidExample:
component.Subscribe(
state => state.counter,
(value, prevValue) => print(`Counter changed: ${prevValue}ā${value}`)
);GenerateInfo(): SharedComponentInfo
Generates component metadata
const info = component.GenerateInfo();
print(`Component ID: ${info.ServerId}`);ResolveIsSyncForPlayer(player: Player, data: SyncPatch<S>): boolean
Controls state sync permissions
// Override to customize:
ResolveIsSyncForPlayer(player, patch) {
return true;
}ResolveSyncForPlayer(player: Player, data: SyncPatch<S>): SyncPatch<S>
Filters/modifies state before syncing
ResolveSyncForPlayer(player, patch) {
return patch
}ResolveConnectionPermission(player: Player): boolean
Determines whether a player is authorized to establish a connection to this shared component instance
ResolveConnectionPermission(player, patch) {
return patch
}AttachDevTool(): void
Enables debugging interface
component.AttachDevTool(); // Sends the state in the REFLEX_DEVTOOLS eventDisableDevTool(): void
Disables debugging tools
component.DisableDevTool();GetIsConnected(): boolean
š„ļø Client-only
Checks if component is connected to network
if (component.GetIsConnected()) {
print("Component is actively connected!");
}Connect(): void
š„ļø Client-only
Establishes network connection to the server
component.Connect(); Disconnect(): void
š„ļø Client-only
Terminates network connection to the server
component.Disconnect(); IsConnectedPlayer(player: Player): boolean
š„ļø Server-only
Checks if specific player is connected
if (component.IsConnectedPlayer(player)) { ... }GetConnectedPlayers(): ReadonlySet<Player>
š„ļø Server-only
Returns set of connected players
const players = component.GetConnectedPlayers();DisconnectPlayer(player: Player): void
š„ļø Server-only
Force disconnects specific player
component.DisconnectPlayer(player);OnConnected(): void
š„ļø Client-only
Fired when client component successfully connects
OnConnected() {
...
}OnDisconnected(): void
š„ļø Client-only
Fired when client component disconnects
OnDisconnected() {
...
}OnConnectedPlayer(player: Player): void
š„ļø Server-only
Fired when new player connects
OnConnectedPlayer(player: Player) {
...
}OnDisconnectedPlayer(player: Player): void
š„ļø Server-only
Fired when player disconnects
OnDisconnectedPlayer(player: Player) {
...
}š Protected Members
remotes: Record<string, ISharedNetwork>
Network communication interface
protected remotes = {
EventName: SharedComponentNetwork.event<[param1: type]>(),
ActionName: SharedComponentNetwork.action<[params], returnType>()
};state: S
Initial state declaration
protected state = {
value: 0,
items: [] as string[]
};isBlockingServerDispatches: boolean
š„ļø Client-only
When true, blocks all state updates from server
// Client code example
protected isBlockingServerDispatches = true; // Pause updates
// Later...
this.isBlockingServerDispatches = false; // Resume updatesisAutoConnect: boolean
š„ļø Client-only
When true (default), automatically connects on component initialization
// Disable auto-connect
protected isAutoConnect = false;
// Manual connection later
this.Connect(); šļø Decorators
@Action()
Marks state-modifying methods
@Action()
public increment(amount: number) {
return {
...this.state,
value: this.state.value + amount
};
}@Subscribe()
Auto-subscribes methods to state changes
@Subscribe(state => state.value)
private onValueChange(value: number) {
// Called only when value changes
}š Networking Utilities
SharedComponentNetwork
event<T extends unknown[]>()
Creates type-safe network event
const event = SharedComponentNetwork.event<[message: string, priority: number]>();action<Args extends unknown[], Return>()
Creates type-safe network action
const action = SharedComponentNetwork.action<[id: string], boolean>();ā ļø Important Notes
Always return new state objects in actions or on dispatch:
// ā
Good
return {
...state,
value: newValue
};
// ā Bad
state.value = newValue;
return state;