-
Notifications
You must be signed in to change notification settings - Fork 100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
hox v2 RFC #37
Comments
有点没明白这个 ref 的使用方法,不知道是不是我理解的这样: const Foo = () => {
const counterModelRef = useRef(null)
return (
<CounterModel.Provider ref={counterModelRef}> // 通过 ref 的方式获取
{counterModelRef.current.xxx}
</CounterModel.Provider>
)
} 如果是这样的话这个命名上会不会和 是不是可以搞一个 |
本来就是 forwardRef 的,何谈命名冲突呢。。
|
改成这样的api和constate这些用context的库有什么区别呢 1。即便可以通过 custom renderer 解决,但是又会导致包体积较大。
|
手动添加Provider?那对于数量不确认的叶子节点呢? |
v2 啥时候出,不能配合 context 很恼火,react-router 里的 hooks 都不能用 |
这样的改动违背了最初的设计理念,不叫modal了确实叫store了,称不上是下一代的状态管理库了,和其它context的库有什么区别呢? |
从V2 整体 更新点 和 解决的问题来看 不管v2怎么样,我觉得保持API简洁,初心不丢最主要...要不 和其他的两个相比,要差异化竞争就比较困难了... |
看了下 unstated-next API,感觉我们就是多了一个 memo,其它的几乎一样。 我给个极简思路,我们只在 v1 基础上提供一个 Provider,如果用户使用了 Provider,我们就把 model 挂在这个 Provider 上。如果没有提供,则保持 v1 的逻辑。 |
保持v1的逻辑,context #20 #36 的问题 怎么解决? unstat-next的 provider后 API使用比较不雅,如果和recoil 类似,只在root根上加个provider, 其余仍保持 v1的 api 是可以接受的。 仔细和recoil使用场景对比了下,recoil能解决的问题,hox基本能解决,recoil和react原生配合的更默契些,比如和suspense的使用,API较复杂,学习成本较高。hox在逻辑复用上要更方便,API简单,学习成本较低。 |
Context方式实现的化,Provider好像必不可少啊,添加 Provider的写法很啰嗦,再想想看还有没有别的办法吧。 |
既然基于Context,为什么我不直接用Context,兜兜转转又回来了? |
v2 看起来真的还不如 unstated-next 来的实在,还简单快捷; |
相比起redux-like的解决方案,我现在反而更喜欢jotai/recoil这种 |
如果应用的最外层加一个 |
PR 已提 #90,欢迎大家来 review~ |
加入 Context 后,hox@v2 多了对局部共享 store 的支持,自由划定共享数据的界限,很 nice 确实会产生 Provider 嵌套问题,对此目前建议的方案为 HoxRoot,使用体验类似 v1 不过这个模式相当于强制全局共享了,也丢失了对局部状态共享的支持 另外,Provider 的嵌套衍生的问题是,共享模块之间会有依赖顺序关系的限制 <AProvider>
<BProvider>
只能 B 依赖 A,无法反向依赖
</BProvider>
</AProvider> 这个依赖顺序限制与 v1 的顺序无关有所不同,虽然新的优势为可以避免依赖产生的问题,但一定程度上也降低自由度 循环依赖的问题个人理解留给用户考虑更好一些,hox 可以做一些循环更新检测的告警和阻断,但机制上允许循环依赖 结合以上和目前的 v2 文档,个人感觉有下边的这些问题
针对这些问题,我理想中的 hox 大概是这样 import { createStore, HoxRoot, createHoxContext } from 'hox'
// 全局 store:依赖 <HoxRoot> 的创建,且有 .data 功能
const useGlobal = createStore(() => {...}) // 默认是全局
const jsx_global = (
<HoxRoot>
/* 内部可访问 useGlobal */
</HoxRoot>
)
// 局部 store - 定义方式 1:依赖 <useStore.Provider> 的创建,无 .data 功能
const useScoped_1 = createStore(() => { ... }, {
context: true // 声明为局部 store,内部自动创建上下文
})
const jsx_scoped_1 = (
<useStore.Provider>
/* 内部可访问 useScoped_1 */
</useStore.Provider>
)
// 局部 store - 定义方式 2:依赖 <customContext.Provider> 的创建,无 .data 功能
const customContext = createHoxContext()
const useScoped_2 = createStore(() => { ... }, {
context: customContext // 声明为局部 store 且指定上下文
})
const useScoped_3 = createStore(() => { ... }, {
context: customContext // 声明为局部 store 且指定上下文
})
const jsx_scoped_2 = (
<customContext.Provider>
/* 内部可访问 useScoped_2、useScoped_3,且两者可以相互依赖 */
</customContext.Provider>
) 以上设计有如下收益
|
@CJY0208 我来回复一下~
可能是我文档没写清楚,其实局部状态和全局状态并不是二选一的,用户可以同时
这一点我觉得有利有弊,创建 store 存在两个函数,的确有认知成本,但是带来的好处是更加明确,用户也能很清楚的分辨出哪些是全局状态哪些是局部状态,甚至在做代码搜索的时候,直接搜索 你提到了通过手动指明 context 的方式来实现,感觉是想解决局部状态一次性声明一批的这种情况?例如下面这种: <AStore.Provider>
<BStore.Provider>
<CStore.Provider>
...
</CStore.Provider>
</BStore.Provider>
</AStore.Provider> 如果用 const fooContext = createHoxContext()
<fooContext.Provider>
...
</fooContext.Provider> 对于一些复杂情况(比如复杂页面中一连串声明五六个 store,我就遇到过这种情况),这样写应该会更简单,但是如果强制每次都得先创建一个 hox context,再创建 store,可能就有些繁琐了,而且,不利于 store 的细粒度组合,举个例子: <AStore.Provider>
<BStore.Provider>
...
</BStore.Provider>
</AStore.Provider>
<AStore.Provider>
<CStore.Provider>
...
</CStore.Provider>
</AStore.Provider> 在页面 1 中,我希望把 A 和 B 组合起来使用,在页面 2 中,我希望把 A 和 C 组合起来使用,这种情况下,AStore 的 我在想 StoreProvider 嵌套地狱的这种情况肯定会存在的,如果要解决的话,倒是有另外一种思路,提供一个批量 Store 的语法糖: <BatchStoreProvider members={[AStoreProvider, BStoreProvider]}>
...
</BatchStoreProvider> 和预先声明 context 的思路不同, 不过,就像你说的,相较于预先声明 context,自然这里就没有办法自动处理 Provider 之间的依赖顺序了:
需要让用户手动按先后顺序排放好。或者也许有办法实现自动判断依赖顺序,但是比较难实现……? 其实我觉得依赖顺序倒还好,我在实际使用过程中(因为我之前大量使用了 reto),几乎没有因为依赖顺序而花费过心思,显示的声明 Store 的顺序也让我能够更清晰的看到整个状态树的脉络,反倒挺好的。 |
OK, 赞成 这种做法应该可以实现依赖顺序无关,之前我做过类似的事情 |
const [useFooStore] = createGlobalStore(...)
const [useBarStore, BarStoreProvider] = createStore(...) |
这样设计 API 的话,倒是有个额外的好处,如果后面的版本 |
依赖了数组的解构,后续拓展可能也会受数组顺序限制😂 |
2-3 个的话,用数组解构还好,多了的话就比较难受了 |
也许可以把 const useFooStore = createGlobalStore(...)
useFooStore.data
// ⬇️
const [useFooStore, getFooStore] = createGlobalStore(...) 这样有些好处:
但也有坏处:
|
npm 包 |
背景
在 hox v1 中,我们的实现方案是在应用的 React 组件树之外,额外创建一个组件树,以存储 hox 中的 model。然而,这种方案渐渐显露出较多的弊端:
为了解决上述问题,在此 RFC 中,尝试将底层实现改为基于 Context。不过基于 Context 虽然可以解决上述全部问题,但也会存在一些新的弊端:
API
创建 model
提供 model
获取/订阅 model
只读(对应 v1 API 中的
useXxxModel.data
)传参
由于存在参数传递,需要给
createModel
增加一个options.memo
参数来控制何时触发重渲染:如果语法较为复杂的话,可以考虑把
memo
的默认值设置为true
,因为绝大部分场景下都是需要 memo 的。其他
是叫 model 好还是叫 store 好?
The text was updated successfully, but these errors were encountered: