UI 开发有两个问题:
展示复用目前基本使用组件化来解决,逻辑复用一直以来都没有特别好的解决方案。React 从一开始的 mixin ,到 高阶组件 以及 Render Props ,都是在试图解决这个问题,但是都引入了一些别的问题。 Mixins
Higher-order Components
Render Props(Vue 中的 Renderless Components)
Hooks在前段时间 Hooks 发布后,我认为 React 找到了【有状态】组件【函数式】【复用逻辑】的解决方案。 实现hooks 给人最直接的印象就是可以在 function 组件中使用 state 了。但它也有着不同于 class 组件的心智模型,从生命周期的思维跳到 update circle,刚开始 useEffect 总会写一些无限循环。接下来我们先来写一个简易版的 useState,来模仿 React。 let state; function useState(init) { function setState(newState) { if (typeof newState === "function") { // 支持旧值传入更新 state = newState(state); } else { state = newState; } // setState 后调用组件 render // render(); } if (!state) { state = init; } return [state, setState]; } 上面就是一个 useState 了,接下来继续写 useEffect. let _deps; function useEffect(callback, deps) { if ( deps === undefined || // 就是不传 deps,就是每次都执行副作用 (deps !== undefined && _deps === undefined) || // 就是初始化,要执行一次副作用 !deps.every((dep, i) => dep === _deps[i]) // 如果不是每一项都相等,就执行 ) { callback(); } } 这就是 useEffect 基本实现了,当然还有一个问题,callback 的 return 函数问题。 let _deps; function useEffect(callback, deps) { if ( deps === undefined || // 就是不传 deps,就是每次都执行副作用 (deps !== undefined && _deps === undefined) || // 就是初始化,要执行一次副作用 !deps.every((dep, i) => dep === _deps[i]) // 如果不是每一项都相等,就执行 ) { // 如果有 cleanUp 就执行清理 if (typeof _deps._cleanUp === "function") { _deps._cleanUp(); } _deps._cleanUp = callback(); } } 接下来,还有个重要问题,hooks 的顺序问题,其实就是把 state 和 deps 存到数组里。 let _arr = []; let cursor = 0; function useState(init) { const current = cursor; function setState(newState) { if (typeof newState === "function") { // 支持旧值传入更新 _arr[current] = newState(_arr[current]); } else { _arr[current] = newState; } // setState 后调用组件 render render(); } if (!_arr[current]) { _arr[current] = init; } cursor++; return [_arr[current], setState]; } function useEffect(callback, deps) { const effect = _arr[cursor] || {}; const { _deps, _cleanUp } = effect; if ( deps === undefined || // 就是不传 deps,就是每次都执行副作用 (deps !== undefined && _deps === undefined) || // 就是初始化,要执行一次副作用 !deps.every((dep, i) => dep === _deps[i]) // 如果不是每一项都相等,就执行 ) { // 如果有 cleanUp 就执行清理 if (typeof _cleanUp === "function") { _cleanUp(); } effect._cleanUp = callback(); effect._deps = deps; _arr[cursor] = effect; } cursor++; |
|