react的state和useState你了解多少?带你深入react state useState

state和useState是react中很重要的概念,虽然笔者一直在用,但是总感觉有些地方认识不够透彻。于是乎,笔者重新阅读学习了react官方文档,感觉受益匪浅。希望能用尽量通俗简洁的语言把吸收的知识表述清楚,便写下此文。

如有错误,欢迎指正~

目录

state

普通变量

深入了解state

useState

基本用法

set函数触发重新渲染

*state--快照(重要!)

 例一

例二 

例三

例四:更新函数 

例五

总结


state

普通变量

当我们需要数据响应式渲染到页面上时,我们就不能使用普通的变量了:

  1. 普通变量无法在多次渲染中持久保存:当 React 再次渲染这个组件时,它会从头开始渲染——不会考虑之前对局部变量的任何更改。
  2. 更改局部变量不会触发渲染。 React 没有意识到它需要使用新数据再次渲染组件。

此时,我们就需要useState来声明state去解决上面的问题。

深入了解state

官网中说到:“State是隔离私有的”,那么这句话应该如何理解呢?

隔离:State 是屏幕上组件实例内部的状态。换句话说,如果你渲染同一个组件两次,每个副本都会有完全隔离的 state!改变其中一个不会影响另一个。

私有:与 props 不同,state 完全私有于<声明>它的组件。父组件无法更改它。

//隔离:son组件渲染两次,两个son组件中的state互相隔离,互不影响
//私有:parent不知道son组件中的state的任何信息,无法改变son组件的state(符合react的单项数据流动特性)

    
    

useState

基本用法

useState 返回一个由两个值组成的数组:

当前的 state:在首次渲染时,它将与你传递的 initialState 相匹配。
set 函数:它可以让你将 state 更新为不同的值并《触发重新渲染》。

const [state, setState] = useState(initialState);

set函数触发重新渲染

在react中,触发组件渲染有两种情况:

  1. 组件的 初次渲染:调用render函数
  2. 组件(或者其祖先之一)的 状态发生了改变:调用set函数

在使用set函数之后,react会从该state声明(useState)的组件开始,根据更改后的state,重新渲染该组件&所有子组件。

*state--快照(重要!)

为了更好的理解,我们可以把state理解为一张快照:当 React 调用你的组件时,它会为特定的那一次渲染提供一张 state 快照。你的组件会在其 JSX 中返回一张包含一整套新的 props 和事件处理函数的 UI 快照 ,其中所有的值都是 根据那一次渲染中 state 的值 被计算出来的。

react的state和useState你了解多少?带你深入react state useState_第1张图片

为了更好的理解,我们接下来看几个例子

 例一

该例子是一个简易计数器,click事件里面调用了三次setNumber,当我们点击按钮之后会发生什么呢?

react的state和useState你了解多少?带你深入react state useState_第2张图片

//App.js
import { useState } from 'react';

export default function Counter() {
  const [number, setNumber] = useState(0);

  return (
    <>
      

{number}

) }

点击之后发现,每次点击值只增加1,而非3。这是为什么呢?

我们来捋一下:

step1:该组件第一次渲染时,number的值是0,所以后续的渲染都是根据0这个值进行的计算。

step2:第一次组件渲染完成后,我们看下的onClick函数:

以下是这个按钮的点击事件处理函数通知 React 要做的事情:

  1. setNumber(number + 1)number 是 0 所以 setNumber(0 + 1)
    • React 准备在下一次渲染时将 number 更改为 1
  2. setNumber(number + 1)number 是0 所以 setNumber(0 + 1)
    • React 准备在下一次渲染时将 number 更改为 1
  3. setNumber(number + 1)number 是0 所以 setNumber(0 + 1)
    • React 准备在下一次渲染时将 number 更改为 1

尽管你调用了三次 setNumber(number + 1),但在 这次渲染的 事件处理函数中 number 会一直是 0,所以你会三次将 state 设置成 1。这就是为什么在你的事件处理函数执行完以后,React 重新渲染的组件中的 number 等于 1 而不是 3

所以我们在第一次渲染之后,onClick函数可以等价为如下代码: 

例二 

我们把上面的例子改一下,再预测一下会出现什么结果:

react的state和useState你了解多少?带你深入react state useState_第3张图片

 

//App.js
import { useState } from 'react';

export default function Counter() {
  const [number, setNumber] = useState(0);

  return (
    <>
      

{number}

) }

点击之后发现:数字从0变成5了,但是弹窗的数依旧是0。

根据我们上面提到的快照理解,上面的onClick代码可以等价为:

这样是不是就很好理解了。

例三

我们再改一下:如果我们加一个定时器,想让弹窗在组件重新渲染 之后 才触发,又会怎样呢?

react的state和useState你了解多少?带你深入react state useState_第4张图片

//App.js
import { useState } from 'react';

export default function Counter() {
  const [number, setNumber] = useState(0);

  return (
    <>
      

{number}

)

结果: 数字从0变成5了,但是三秒之后的弹窗的数依旧是0。

这是为什么呢?我们看react官方如何解释:

一个 state 变量的值永远不会在一次渲染的内部发生变化, 即使其事件处理函数的代码是异步的。”

React 会使 state 的值始终”固定“在一次渲染的各个事件处理函数内部。

state作为快照,它的值在 React 通过调用你的组件“获取 UI 的快照”时就被“固定”了,哪怕是异步代码,它得到的state值也是在调用时被固定的快照的值。

所以对应函数等价于如下代码:

setNumber(0 + 5);
setTimeout(() => {
  alert(0);
}, 3000);

例四:更新函数 

让我们回到例一,如果我们想在onClick里面写三个set函数来实现加3的效果,那该如何改造呢?

这时候就需要用到更新函数了:在set函数中,传入一个根据队列中的前一个 state 计算下一个 state 的 函数。

简单来说,就是把set函数的参数,从之前的一个值/变量,换成一个函数即可。

更改后的代码见下图:

react的state和useState你了解多少?带你深入react state useState_第5张图片

 这样,每点击一次,加的就是3了。

详细更新过程见下图:

react的state和useState你了解多少?带你深入react state useState_第6张图片

例五

我们再升级一下例4的代码,运行结果会怎样呢?

react的state和useState你了解多少?带你深入react state useState_第7张图片

结果:点击按钮后,从0变成了42。 

详细更新过程见下图:

react的state和useState你了解多少?带你深入react state useState_第8张图片

 

总结

  • 调用set函数会请求一次新的渲染
  • 每个渲染(以及其中的函数)始终“看到”的是 React 提供给这个 渲染的 state 快照
  • 过去创建的事件处理函数拥有的是创建它们的那次渲染中的 state 值。
  • React 会等到事件处理函数中的 所有 代码都运行完毕再处理你的 state 更新。
  • 要在一个事件中多次更新某些 state,你可以使用 setNumber(n => n + 1) 更新函数。

你可能感兴趣的:(react.js,前端,javascript,前端框架,react)