https://github.com/tearlighting/react-provider-factory-pattern
https://github.com/tearlighting/react-provider-factory-pattern
Last synced: 4 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/tearlighting/react-provider-factory-pattern
- Owner: tearlighting
- Created: 2025-09-19T02:36:25.000Z (9 months ago)
- Default Branch: main
- Last Pushed: 2025-09-19T02:38:04.000Z (9 months ago)
- Last Synced: 2025-09-19T04:27:21.099Z (9 months ago)
- Size: 2.93 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# react-provider-factory-pattern
🧪 Experimental pattern for React state management:
**Factory (closure) + Provider + useSyncExternalStore = Polymorphic Store with fine-grained updates**
---
## Motivation
- React Context 默认全量 re-render,不适合大表单/大列表场景。
- Zustand/Jotai 这类库解决了一部分,但抽象层次固定。
- 我想尝试:**把 store 本身抽象为工厂**,然后用 Provider 注入,这样可以:
- 支持多个 store 实例(多态)
- 用 `useSyncExternalStore` 保证 selector 精细化更新
- store 内部实现可以自由切换(闭包 / reactive-core / 其他)
---
## Example
```tsx
import React, { createContext, useContext, useRef } from "react"
import { useSyncExternalStore } from "react"
// ---- Store Factory ----
function createCounterStore() {
let state = { count: 0 }
const listeners = new Set<() => void>()
const getState = () => state
const setState = (partial: Partial) => {
state = { ...state, ...partial }
listeners.forEach(l => l())
}
const subscribe = (listener: () => void) => {
listeners.add(listener)
return () => listeners.delete(listener)
}
return { getState, setState, subscribe }
}
// ---- Hook creator (selector support) ----
function createUseStore(store: ReturnType) {
return function useStore(selector: (s: T) => Selected): Selected {
return useSyncExternalStore(
store.subscribe,
() => selector(store.getState()) // only re-render if selector result changes
)
}
}
// ---- Provider Pattern ----
const CounterContext = createContext | null>(null)
export function CounterProvider({ children }: { children: React.ReactNode }) {
const storeRef = useRef(createCounterStore())
return {children}
}
export function useCounter(selector: (s: { count: number }) => Selected): Selected {
const store = useContext(CounterContext)!
return createUseStore(store)(selector)
}
// ---- Usage ----
function Display() {
const count = useCounter(s => s.count)
return
Count: {count}
}
function Controls() {
const store = useContext(CounterContext)!
return (
store.setState({ count: store.getState().count + 1 })}>
Increment
)
}
export default function App() {
return (
)
}
```
## Key Points
createCounterStore → 工厂函数,返回闭包 store。
useSyncExternalStore → 保证 selector 精细化更新。
Provider → 注入多态 store 实例,不同 Provider = 不同 store。
useCounter(selector) → 组件只关心自己订阅的片段。
## TODO
More demos (forms, nested providers).
Benchmark vs Zustand/Jotai.
Try swapping the factory core (e.g. Vue's reactive) inside.