简单实现React的useState钩子

  一段时间没用React,重新温习了一遍官网新特性hooks的内容,干脆自己写个简单的,方便记忆一些官网列出的注意事项。

      const makeUseState = () => {         const newOne = stateAmount => ({           index: 0,           whole: stateAmount,           data: [],           getData(initData) {             let i = this.index;             this.index = (i + 1) % this.whole;             return [this.data[i] ? this.data[i] : (this.data[i] = initData), this.setData(i)];           },           setData(index) {             return (newData, reRender) => {               this.data[index] = newData;               reRender();             };           }         });         const rootState = {};         return (data, CpName, seq, stateAmount) => {           if (rootState[CpName] === undefined) {             rootState[CpName] = [];           }           let store = rootState[CpName];           if (!store[seq]) {             store[seq] = newOne(stateAmount);           }           return store[seq].getData(data);         };       };       const myUseState = makeUseState();       const N = props => {         const { seq, testDiff, update } = props;         // 后面三个参数解析模板字符串时添加         const [A, setA] = myUseState('123', 'N', seq, 2);         const [B, setB] = myUseState('123', 'N', seq, 2);         const tmout = testDiff === '一' ? 2000 : 4000;         return (           <div>             第{testDiff}个函数组件:             <br />             <button onClick={() => setA('123A', update)}>更新</button>             <br />             A= {A}             <br />             <button onClick={() => setB('123B', update)}>更新</button>             <br />B = {B}           </div>         );       };       class M extends Component {         render() {           return (             <div>               {/* seq,update为解析模板字符串时添加 */}               <N seq={0} update={() => this.setState({})} testDiff="一" />               <N seq={1} update={() => this.setState({})} testDiff="二" />             </div>           );         }       }       ReactDOM.render(<M />, app);

  记得刚开始用React的时候,各种项目都用函数组件,根本停不下来,简洁明快,即插即用,简直是懒癌患者的福音,然后慢慢要接触到需要状态实例化的场景。

  由于当时的应用场景是,即同一页面不用到两个相同的函数组件,于是继续偷懒,在父类组件的卸载钩子里重置了下函数组件的状态,这样即使切换页面,也看不出破绽,乍一看,好像还实现了有状态组件的功能,后来自己用得都觉得别扭,用行话说,就是不够优雅(我跟你谈进度你跟我谈优雅?!)。特意去官网看了下,有种叫mixin(不是sass的@mixin)的方式和我实现的方式有点像,本质上好像还是脱离不了复制粘贴的嫌疑,什么?!你不怕被面向对象编程的程序员深深地鄙视?老夫行走江湖多年,靠的就是两大神技,一个ctrl+c,一个ctrl+V?恭喜你,赢得了单身汪的尊严和丰满的发量,不过俗话说的好,no think,no gain ,理解往往是最高效的记忆方式。

  刚开始使用useState其实我是拒绝的,心里总有种不安感,就像往拆迁楼的破窗内扔石头,当下扔的时候听到声音了,紧接着心里就会后怕,下次敲代码的时候手都在哆嗦,为啥useState要按顺序索引?为啥中间不能嵌套if判断?

  函数组件肯定是没法跟类组件比的,短小精悍却没法繁衍后代确实是一大憾事,啥都得亲自上阵,一不小心数据就串重了,那么,当然也不可能大费周章用类似Vux,Redux一样专门建个数据中心,简而言之,言而简之,好像用闭包就能搞定,闭包不就是专门用来制造便携式数据仓库的吗?

  首先说下一些个人理解,像 babel 这些将 js,jsx,es都给转成 AST 语法,本质上不就是模板字符串解析吗?函数组件既然没有状态,可以通过模板字符串来记住每个函数组件的编号,这样不管是同类函数组件的哪一个更新,都能对应到自身的state。在我看来,用了useState的函数组件,将视图层和数据层分离得更加明显,条理清晰,便于阅读,将一个个state实例化的过程隐藏到了幕后,这样无疑大大提高了开发人员的工作效率(少敲代码 !== 提高效率)。

  废话说了那么多,说下不能用判断条件分割 useState 的原因,毕竟这也是官网特意强调要注意的:

  从上面demo的实现方式基本可以体现我的观点,对于react具体怎么样实现useState我并不清楚原理,只是根据需求实现了一个类似的效果。按照我的实现方式,代码在编译阶段(转义阶段),要对不同的函数组件以及调用次数进行排序编号,即便写在判断条件内的useState也会被置入数组,事实上,在代码 运行阶段,根本也无从判断这个useState是否要走完一轮循环,这可能也是官网强调useState不能放入判断条件的原因,另一方面,也是因为采用数组存储数据的方式决定了一旦不按下标重复遍历数组,就可能出错。

  话说回来,框架的本质不就是利用了各成一家的模板字符串语法来创造便利的代码书写方式吗?希望未来,这些国外洋厂的开发者能给我这类懒癌患者带来更多的福音!

上一篇:useState原理解析


下一篇:React中,useReducer和useState