원클릭으로
refrakt
How to use Refrakt signals-based state management library
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
How to use Refrakt signals-based state management library
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
| name | refrakt |
| description | How to use Refrakt signals-based state management library |
Refrakt is a lightweight state management library built on TC39 signals.
refrakt — curated entry point: re-exports the primary constructors and core typesrefrakt/signal.js — signal primitives: signal, computed, effect, untrackrefrakt/reducer.js — pure reducer-based state: reducer, withLoggingrefrakt/store.js — transactional state with effects: store, tx, noFx, withLoggingrefrakt/send.js — action utilities: forwardrefrakt/scope.js — scoped child stores: scoperefrakt/iter.js — async iterator utilities: mergeAsync, sequenceAsync, mapAsyncrefrakt/never.js — exhaustiveness helpers: assertNever, NeverErrorUse reducer when you only need state transitions with no side effects.
import { type Reducer, reducer } from "refrakt/reducer.js";
import { assertNever } from "refrakt/never.js";
type Action = { type: "increment" } | { type: "decrement" };
const update: Reducer<number, Action> = (state, action) => {
switch (action.type) {
case "increment":
return state + 1;
case "decrement":
return state - 1;
default:
return assertNever(action);
}
};
const counter = reducer(update, 0);
counter.send({ type: "increment" });
counter.get(); // 1
Use store when you need side effects. The update function returns a transaction via tx(state, fx?). Effects are async generators that yield actions back to the store. The state() callback passed to fx reads current store state — use it to check flags and cancel effects.
import { type Update, store, tx } from "refrakt/store.js";
import { assertNever } from "refrakt/never.js";
type Model = { isRunning: boolean; elapsed: number };
type Action = { type: "start" } | { type: "stop" } | { type: "tick" };
const update: Update<Model, Action, void> = (state, action) => {
switch (action.type) {
case "start":
return tx(
{ ...state, isRunning: true } as Model,
async function* (state) {
while (state().isRunning) {
await delay(1000);
if (state().isRunning) {
yield { type: "tick" };
}
}
},
);
case "stop":
return tx({ ...state, isRunning: false } as Model);
case "tick":
return tx({ ...state, elapsed: state.elapsed + 1 } as Model);
default:
return assertNever(action);
}
};
const myStore = store(update, { isRunning: false, elapsed: 0 });
Pass a third argument to store for dependency injection:
const update: Update<Model, Action, { api: Api }> = (
state,
action,
context,
) => {
switch (action.type) {
case "fetch":
return tx({ ...state, loading: true } as Model, async function* () {
const data = await context.api.getData();
yield { type: "set", data };
});
// ...
}
};
const myStore = store(update, initialState, { api: myApi });
import { signal, computed, effect, untrack } from "refrakt/signal.js";
const count = signal(0);
const doubled = computed(() => count.get() * 2);
// Effects are batched to microtask
const cleanup = effect(() => {
console.log(count.get());
});
// Read without tracking
const value = untrack(() => count.get());
Create a child store that projects a subset of parent state and maps actions:
import { scope } from "refrakt/scope.js";
const child = scope({
store: parentStore,
get: (state) => state.child,
tag: (action) => ({ type: "child", action }),
});
Transform a send function to tag actions:
import { forward } from "refrakt/send.js";
const sendChild = forward(parentStore.send, (action) => ({
type: "child",
action,
}));
assertNever(action) (from refrakt/never.js) in the default arm. TypeScript will error if the switch isn't exhaustive.state() inside fx to read current state. Check a flag (e.g. isRunning) to break out of loops.as Model assertions: Use as Model when spreading state in tx() calls to help TypeScript infer the transaction type.