단일 경로
모든 상태 변경은 Intent → Command → Executor → Event → Store를 거쳐요. 지름길도, 예외도 없어요.
단일 경로
모든 상태 변경은 Intent → Command → Executor → Event → Store를 거쳐요. 지름길도, 예외도 없어요.
예측 가능
Event는 사실을 기록해요. 상태 전이는 순수 함수예요. 무엇이 일어났고 왜 일어났는지 항상 알 수 있어요.
TypeScript 우선
executor 입력부터 Event 페이로드까지 완전한 타입 추론. 수동 타입 어노테이션이 필요 없어요.
모든 레이어에서 테스트 가능
다섯 가지 테스트 유틸리티가 특정 레이어를 대상으로 해요: TestStore, TestExecutor, TestReducer, TestComputed, TestIntent.
Intent (사용자가 하고 싶은 것) → Command (실행할 것) → CommandExecutor (사이드 이펙트 경계) → emit(Event) (일어난 일을 기록) → Store.on (순수 상태 전이) → Computed (파생 상태, 즉시 재계산) → 구독자 알림단순한 카운터 증가든 에러 처리가 포함된 복잡한 비동기 API 호출이든, 모든 상태 변경은 이 정확한 경로를 따라요.
| 패키지 | 설명 |
|---|---|
@hurum/core | 핵심 상태 관리. 프레임워크 무관, 의존성 제로. |
@hurum/react | React 바인딩: Provider, useStore, Store.use.*, withProvider. |
import { Store, Events, Event, CommandExecutor, Intents, Intent } from '@hurum/core'
// 1. Define events (what happened)const CounterEvent = Events('Counter', { incremented: Event<{ amount: number }>(),})
// 2. Define executor (side-effect boundary)const [IncrementCommand, IncrementExecutor] = CommandExecutor< { amount: number }>((command, { emit }) => { emit(CounterEvent.incremented(command))})
// 3. Define intent (what the user wants)const CounterIntents = Intents('Counter', { plusClicked: Intent(IncrementCommand),})
// 4. Define store (state + transitions + everything)const CounterStore = Store({ state: { count: 0 } }) .on(CounterEvent, { incremented: (state, { amount }) => ({ ...state, count: state.count + amount }) }) .computed({ doubled: (state) => state.count * 2 }) .intents(CounterIntents) .executors(IncrementExecutor)// 5. Use in Reactfunction Counter() { const count = CounterStore.use.count() const doubled = CounterStore.use.doubled()
return ( <div> <p>{count} (doubled: {doubled})</p> <button onClick={() => CounterStore.send.plusClicked({ amount: 1 })}>+1</button> </div> )}