-
Notifications
You must be signed in to change notification settings - Fork 98
Closed
Description
背景
在 hox v1 中,我们的实现方案是在应用的 React 组件树之外,额外创建一个组件树,以存储 hox 中的 model。然而,这种方案渐渐显露出较多的弊端:
- 对渲染环境的要求比较苛刻,强依赖 react-dom,SSR、RN、小程序都无法使用(rn #10 nextjs 中使用不了 #11 微信小程序框架Remax中无法使用 #13)。即便可以通过 custom renderer 解决,但是又会导致包体积较大(v1.1.0 引入 react-reconciler 后的体积徒增问题 #26)。
- 无法和 Context 配合使用,在某些场景下瓶颈非常明显(与上下文 Context 以及 useContext 的配合问题 #20 与umi 的 useRequest 一起使用时,捕获不到全局错误 #36)
- 生命周期不够完善,无法控制何时装载何时卸载(是否需要提供一个 unmount 的 API,在微前端场景,需要卸载数据 #12)
- 强制将数据存储到全局,无法支持局部状态
为了解决上述问题,在此 RFC 中,尝试将底层实现改为基于 Context。不过基于 Context 虽然可以解决上述全部问题,但也会存在一些新的弊端:
- API 较为复杂,特别是需要用户手动在组件树中添加 Provider
API
创建 model
import {createModel} from 'hox'
function useCounter() {
// ...
}
export const CounterModel = createModel(useCounter)
// 或
export default createModel(useCounter)提供 model
import {CounterModel} from './counter.model.ts'
function App() {
return (
<CounterModel.Provider>
<div>
{/* ... */}
</div>
</CounterModel.Provider>
)
}获取/订阅 model
import {useModel} from 'hox'
import {CounterModel} from './counter.model.ts'
function Foo() {
const counterModel = useModel(CounterModel)
return (
...
)
}只读(对应 v1 API 中的 useXxxModel.data)
<CounterModel.Provider ref={yourModelRef}> // 通过 ref 的方式获取
</CounterModel.Provider>传参
<CounterModel.Provider startFrom={123}> // 通过 ref 的方式获取
</CounterModel.Provider>interface Props {
startFrom: number
}
const CounterModel = createModel<Props>((props) => {
const [count, setCount] = useState(props.startFrom)
// ...
})由于存在参数传递,需要给 createModel 增加一个 options.memo 参数来控制何时触发重渲染:
const CounterModel = createModel<Props>((props) => {
const [count, setCount] = useState(props.startFrom)
// ...
}, { // <- options
memo: true // 开启 memo 后,Provider 的重渲染逻辑和普通 React 组件被 memo 后的逻辑类似
})如果语法较为复杂的话,可以考虑把 memo 的默认值设置为 true,因为绝大部分场景下都是需要 memo 的。
其他
是叫 model 好还是叫 store 好?
Metadata
Metadata
Assignees
Labels
No labels