React的状态管理
1.class组件
在传统的class组件中,react的状态管理大多依赖以下三种方式:
- props
- state
- context
下面来简单说一下以上三种方式
1.props
子组件一般通过父组件传递的props
值来进行相应的展示,自身没有自己的状态。这也造成了一些问题,只有父元素主动触发了props
的修改,受控组件的的渲染才会进行相应的改变,这样的应用场景显然太单薄了,受控组件当然也有需求通过自身的一些变化能够触发自身的重新渲染,最常见的例子input
受控组件输入框,如何做到输入框的值来自于父组件的props
,而当输入框输入内容时又能够更改输入框中显示的值呢?这就要说一说react
的设计思路了,基于jsx
语法的能够直接书写js
代码的组件式开发框架,在react
中可以直接灵活的书写js
代码,这就有了让js
的高阶函数发挥作用的机会了,通过函数的传递,将父组件中更改数据的函数传入子组件中,子组件触发相应的操作时调用该函数,并传入相应的值,就能够做到更改父组件中的数据,这也是函数式编程的优势之一,灵活且强大的抽象能力。这种高阶函数传递的方式也是常说的react
子组件向父组件传递值的方式。
在react
中数据是单向流动的,数据只能从父组件到子组件,而通过高阶函数的方式则能够实现将子组件的值传入父组件中。这对于经常使用js
的人来说是相当熟悉且友好的
2.state
子组件一般不接收props
,自身内部维护自己的state
。组件的重新渲染一般通过调用自己的setState
方法进行,这里说一个老生长谈的问题:react
的setState
方法到底是同步的还是异步的?答案是两种都有,在不同的情况下会有不同的处理方法,总的来说如果是在react
的可控范围内调用该方法,那么该方法就是异步的,这样做的好处是能够批量汇总setState
的调用值,进行state
的一次性更新,能够减少内部重新渲染的次数,有助于提高性能,由于这个原因,在react
的生命周期函数中调用的该方法的的话,此时直接读取state
的值是没有更改的,针对这个问题,react
也提供了相应的解决办法,setState
方法可以跟一个函数,这个函数接收一个参数,这个参数就是当前state
的变化汇总,由于是react
自己实现的,因此这样并不会导致重新渲染却能够获取正确的state
值,而不在react
的可控范围内调用该方法的话就只能是同步的,原因也很好理解,因为当前的调用状态react
已经不可控了,没法进行异步汇总更新。那么什么情况是可控的什么又是不可控呢,简单来说在reatc
的生命周期内触发的话就是可控的,因为调用过程由react
控制,而不在生命周期内触发比如在setTimeout中触发就不可控,因为当前调用setState
的是浏览器的行为,检测的话也比较简单,只需要判断一下当前函数中的this
就行了。
3.context嵌套传值
典型的生产者消费者模式,用以解决react
中祖先组件向子孙组件传递状态时每一层都需要写props
的问题,这既不清晰也不优雅。当然这也造成了新的问题,组件树的嵌套会进一步加深,给人的感觉就像回调地域
2.hook函数
class
组件存在一些小问题,比如class
语法会有一定的复杂度、class
组件的生命周期函数都只有一份这就导致了一个组件有太多的副作用操作时需要将逻辑全部写在该生命周期函数中,虽然可以进行方法抽取,但抽取出来函数一般也是与该组件耦合性较深的,因为该函数一般需要当前组件的内部状态作为副作用的参数,或者直接需要该组件的dom
对象,此外副作用函数与清除副作用的函数不能在视觉上写在一起,造成了后续维护的麻烦,并且由于js
的特性,函数中的this
指向问题也比较绕,基于种种原因,react
在16版本中推出了hook
函数,让以前存在感不是很足的函数组件也能够实现class
组件的生命周期函数功能,在实际体验上做到基本一致。
说一说我知道的hook
函数实现原理,由于函数组件不会使用