You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
importReactfrom'react';importReactDOMfrom'react-dom';letindex=0;constlastStates=[];functionuseState(initialState){lastStates[index]=lastStates[index]||initialState;constcurrent=index;functionsetState(state){lastStates[current]=state;render();}index+=1;return[lastStates[current],setState];}functionApp(){const[count,setCount]=useState(0);const[name,setName]=useState('Mary');console.log(count);return(<div><p>
click
{' '}{count}{' '}
times
</p><p>
name is
{' '}{name}</p><buttontype="button"onClick={()=>{setCount(count+1);}}>+</button><buttontype="button"onClick={()=>{setName(`${Date.now()}`);}}>change Name</button></div>);}functionrender(){index=0;ReactDOM.render(<App/>,document.getElementById('app'));}render();
state Hook——useState
作用
在函数式组件中定义state
useState做了啥
我们可以看到,在此函数中,我们通过useState定义了一个'state变量',它与 class 里面的 this.state 提供的功能完全相同.相当于以下代码。
useState参数
在代码中,我们传入了0作为useState的参数,这个参数的数值会被当成count初始值。当然此参数不限于传递数字以及字符串,可以传入一个对象当成初始的state。如果state需要储存多个变量的值,那么调用多次useState即可
useState返回值
返回值为:当前 state 以及更新 state 的函数,这与 class 里面 this.state.count 和 this.setState 类似,唯一区别就是你需要成对的获取它们。看到[count, setCount]很容易就能明白这是ES6的解构数组的写法。相当于以下代码
读取状态值
只需要使用变量即可
以前写法
现在的写法
更新状态
通过setCount函数更新
以前写法
现在写法
这里setCount接收的参数是修改过的新状态值
声明多个state变量
我们可以在一个组件中多次使用state Hook来声明多个state变量
React 假设当你多次调用 useState 的时候,你能保证每次渲染时它们的调用顺序是不变的
为什么React要规定每次渲染它们时的调用顺序不变呢,这个是一个理解Hook至关重要的问题
注意:useState的初始值,只在第一次有效
举例:
当我点击按钮修改name的值的时候,我发现在Child组件,是收到了,但是并没有通过useState赋值给name!
运行结果:
children里的name始终展示的是rose,点击按钮设置为jack后,也还是显示rose
快照(闭包)vs 最新值
在开始前,先抛出这么一个问题。在 1s 内频繁点击10次按钮,下面代码的执行表现是什么
如果是这段代码呢?它又会是什么表现?
第一个例子,1s内连续点10次,从最开始点击1s后页面上的数字会从0增长到10。而第二个例子中,连续点击10次,页面上的数字只会从0增长到1。
这是为什么呢?其实这主要是引用和闭包的区别
class 组件里面可以通过 this.state 引用到 count,所以每次 setTimeout 的时候都能通过引用拿到上一次的最新 count,所以点击多少次最后就加了多少。
在 function component 里面每次更新都是重新执行当前函数,也就是说 setTimeout 里面读取到的 count 是通过闭包获取的,而这个 count 实际上只是初始值,并不是上次执行完成后的最新值,所以最后只加了1次。
快照和引用的转换
如果我想让函数组件也是从0加到10,那么该怎么来解决呢?聪明的你一定会想到,如果模仿类组件里面的 this.state,我们用一个引用来保存 count 不就好了吗?没错,这样是可以解决,只是这个引用该怎么写呢?我在 state 里面设置一个对象好不好?就像下面这样:
答案是不行,因为即使 state 是个对象,但每次更新的时候,要传一个新的引用进去,这样的引用依然是没有意义。
useRef
想要解决这个问题,那就涉及到另一个新的Hook方法——useRef。useRef是一个对象,它拥有一个current属性,并且不管函数组件执行多少次,而useRef返回的对象永远都是原来那一个。
useRef有下面几个特点:
useRef vs createRef
1、两者都是获取 ref 的方式,都有一个 current 属性。
2、useRef 只能用于函数组件,createRef 可以用在类组件中。
3、useRef 在每次重新渲染后都保持不变,而 createRef 每次都会发生变化。
关于 React.useRef() 返回的 ref 对象在组件的整个生命周期内保持不变,我们来和 React.createRef() 来做一个对比,代码如下:
useState实现原理
参考:
1、React Hooks原理与最佳实践:https://mp.weixin.qq.com/s/DS2OjlwWjClboDIgLFuG6A
The text was updated successfully, but these errors were encountered: