网易首页 > 网易号 > 正文 申请入驻

web前端培训组件内部数据state的知识点分享

0
分享至

创建组件时,我们可以通过 props 接收外部传入的数据,该数据可以称之为组件外部数据。除此之外,React还有一个命脉知识点 -> 组件内部数据:state.

使用函数创建组件时,内部数据 state 通过 useState 定义。

function Coutner() {

// 利用数组结构得到两个变量

// count:表示定义的数据

// setCount:修改该数据的方法

// useState:从闭包数据中取出 count 的值,0 仅表示默认值

const [count, setCount] = useState(0)

return (

{count}

由于目前函数组件足以支撑所有场景的实现,因此写法更为复杂的 class 组件相关知识本系列将不会涉及,有兴趣的同学可以阅读官网了解。现在主流的项目也基本全面采用函数式组件相关解决方案。只有部分落后的项目团队依然在坚持 class 组件。React 提供了方便平滑的升级模式,还在维护老项目的同学可以跟着本系列学习函数组件并逐步重构项目

state 属于被监控的数据,它是 React 实现数据驱动 UI 的核心。当 state 值发生变化时,组件会尝试重新渲染,因此,函数会重新执行一次。函数重新执行后,此时 count 的数据已经是变化后的结果,因此渲染到 UI 的结果也会发生变化。

import { useState } from 'react';

export default function Counter() {

const [count, setCount] = useState(0)

return (

{count}

setCount(count + 1)}>递增

在 TypeScript 中使用 useState 时,我们应该使用如下的方式声明 state 的数据类型

const [count, setCount] = useState

但是通常情况下,基础数据类型能够通过默认值轻松推导出来,因此我们不需要专门设置,只有在相对复杂的场景下才会需要专门声明。

// 能根据 0 推导为 number 类型

const [count, setCount] = useState(0);

// 能根据 false 推导为 boolean 类型

const [visible, setVisible] = useState(false);

// 能根据 [] 推导为 any[] 类型,因此此时还需要专门声明any为何物

const [arr, setArr] = useState

需要注意的是,state 使用浅比较对比新旧数据。也就意味着,当 state 为引用数据类型时,如果你的新数据与旧数据引用相同,那么 React 无法感知到你的数据发生了变化。

例如

import { useState } from 'react';

export default function Counter() {

const [arr, setArr] = useState

function incrementHandle() {

let newArr = arr

newArr.push((arr[arr.length - 1] || 0) + 1)

setArr(newArr)

return (

{arr.map((item) => (

{item}

递增

重点关注该例子中的 incrementHandle 方法。新的数组与旧的数组引用一样,因此就算更改了数组内容,但是 React 无法感知,组件也就不会重新渲染。

因此,正确的方式应该要想办法让新旧数据的引用不同

function incrementHandle() {

let newArr = [...arr]

newArr.push((arr[arr.length - 1] || 0) + 1)

setArr(newArr)

当 state 的数据变得复杂,我们可以借助 immer 等不可变数据集来帮助我们。详情可阅读相关文档

注意,state 是被监控的数据,它与 UI 的变化息息相关。在实践中,还有很多其他的数据与 UI 变化无关,它们不应该放在 state 中来管理,而应该想其他办法。

单向数据流

一个完整的 React 项目由多个组件组合而成。每个组件都是独立的,都可以有自己的外部数据与内部数据。对于父组件来说,它可以把自己的 state 作为 props 向下传递给它的子组件。

这种自上而下的数据流动,我们称之为单向数据流.

任何一个组件的内部数据 state 发生变化,就会影响组件树中低于它的组件。

如果你把一个以组件构成的树想象成一个 props 的数据瀑布的话,那么每一个组件的 state 就像是在任意一点上给瀑布增加额外的水源,但是它只能向下流动。

在实践中,为了避免额外的性能消耗,我们需要精准的把握每一次 state 的更新会影响哪些组件,掌握单向数据流的特性对此非常有帮助。

如果你想要在子组件中,修改父组件传递而来的状态,只能通过修改父组件 state 的方式,修改方法通常也由父组件传递给子组件。

合并

当同一个 state 数据被修改多次时,他们会合并成一次修改。如下面例子,我们调用两次 setCount,执行一次之后,count 变成 2,而不会变成 3

import { useState } from 'react';

export default function Counter() {

const [count, setCount] = useState(0)

function handle() {

setCount(count + 1)

setCount(count + 2)

return (

{count}

递增

当我们同时修改多个 state 时,也会合并起来,被认为是一次修改,组件只会重新渲染一次。

import { useState } from 'react';

export default function Counter() {

const [count, setCount] = useState(0)

const [other, setOther] = useState(0)

function handle() {

setCount(count + 1)

setOther(other + 1)

return (

{count}

{other}

递增

如果同时修改多个 state 的行为发生在异步回调里,React 18 也会把它们合并成为一次 state 操作。

import { useState } from 'react';

export default function Counter() {

const [count, setCount] = useState(0)

const [other, setOther] = useState(0)

function handle() {

setTimeout(() => {

setCount(count + 1)

setOther(other + 1)

}, 500)

return (

{count}

{other}

递增

正确识别闭包

在函数组件中,如果我们在回调函数中使用了 state 的值,那么闭包就会产生。闭包在函数创建时产生,它会缓存创建时的 state 的值。

在很多文章中,把这种现象称为“闭包陷阱”,它是一种正常现象,但是如果你在使用时无法正确识别它,那么会给你带来麻烦。

import { useState } from 'react';

export default function Counter() {

const [count, setCount] = useState(0)

function handle() {

setCount(count + 1)

// 当 setTimeout 执行时,

// 回调函数的 count 值不是 1,而是 0

setTimeout(() => {

setCount(count + 2)

}, 0)

return (

{count}

递增

异步写法

如果我们要在 setTimeout 回调函数中,正确的拿到当前 state 的值,我们可以使用如下的写法来达到目的

import { useState } from 'react';

export default function Counter() {

const [count, setCount] = useState(0)

function handle() {

setCount(count + 1)

setTimeout(() => {

- setCount(count + 2)

+ setCount(count => count + 2)

}, 0)

return (

{count}

递增

实践

接下来,我们完成一个稍微复杂一点的例子

多个滑动条控制div元素的不同属性,如果使用 useState 来实现,应该怎么做?

import React, { useState } from 'react';

import { Slider } from 'antd-mobile';

import './index.scss';

interface Color {

r: number,

g: number,

b: number

export default function Rectangle() {

const [height, setHeight] = useState(10);

const [width, setWidth] = useState(10);

const [color, setColor] = useState

({ r: 0, g: 0, b: 0 });

const [radius, setRadius] = useState

const

height: `${height}px`,

width: `${width}px`,

backgroundColor: `rgb(${color.r}, ${color.g}, ${color.b})`,

borderRadius: `${radius}px`

return (

height:

max={300}

min={10}

onChange={(n) => setHeight(n || 0)}

width:

max={300}

min={10}

onChange={(n) => setWidth(n || 0)}

color: R:

max={255}

min={0}

onChange={(n = 0) => setColor({ ...color, r: n })}

color: G:

max={255}

min={0}

onChange={(n = 0) => setColor({ ...color, g: n })}

color: B:

max={255}

min={0}

onChange={(n = 0) => setColor({ ...color, b: n })}

Radius:

max={150}

min={0}

onChange={(n = 0) => setRadius(n)}

更多Java –大数据 – 前端 – UI/UE - Android - 人工智能资料下载,可访问百度:尚硅谷官网(www.atguigu.com)

聊点高级的

原则上来说,state 的应用知识基本上已经聊完了。不过,作为 React 专家,我还能跟大家聊一点高级的。

state的变化,是异步的。

状态异步,也就意味着,当你想要在setCount之后立即去使用它时,你无法拿到状态最新的值,而到下一个事件循环周期执行时,状态才是最新值。

const [count, setCount] = useState(10);

setCount(20);

console.log(count); // 此时counter的值,并不是20,而是10

实践中有许多错误的使用,会因为这个异步问题出现 bug。

例如我们想要用一个接口,去请求一堆数据,而这个接口接收多个参数。

当改变各种过滤条件,那么就势必会改变传入的参数,并在参数改变时,立即重新去请求一次数据。

我们会很自然的想到使用如下的方式

import React, { useState } from 'react';

interface ListItem {

name: string,

id: number,

thumb: string

// 一堆种参数

interface Param {

current?: number,

pageSize?: number,

name?: string,

id?: number,

time?: Date

export default function AsyncDemo() {

const [listData, setListData] = useState

// 定义一个状态缓存参数,确保每次改变后都能缓存完整的参数

const [param, setParam] = useState({});

function fetchListData() {

// @ts-ignore

listApi(param).then(res => {

setListData(res.data);

function searchByName(name: string) {

setParam({ ...param, name });

// 改变param之后立即执行请求数据的代码

// 这里的问题是,因为异步的原因,param并不会马上发生变化,

// 此时直接发送请求无法拿到最新的参数

fetchListData();

return [

data list

searchByName('Jone')}>search by name

这是一个不完整的例子,代码只能用作参考,需要大家在阅读时结合自身开发经验去体会。

关键的代码在于searchByName方法。当使用setParam改变了param之后,立即去请求数据,在当前循环周期,param并没有改变。请求的结果,自然无法达到预期。

文章转载于小生方勤

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
两家外资银行网点同日关闭,原因却各自不同,花旗中国本月已连关三支行

两家外资银行网点同日关闭,原因却各自不同,花旗中国本月已连关三支行

财联社
2024-06-19 09:32:10
洪水中的梅州:水位逼近三楼,多地成“孤岛”

洪水中的梅州:水位逼近三楼,多地成“孤岛”

极目新闻
2024-06-19 21:17:34
省委书记、省长为新机构揭牌!

省委书记、省长为新机构揭牌!

政知新媒体
2024-06-19 21:15:02
永远不要做压死骆驼的最后一根稻草

永远不要做压死骆驼的最后一根稻草

洞见
2024-06-18 21:48:38
美国开始慌了?中国激光武器颠覆性突破,星链卫星已经不再安全!

美国开始慌了?中国激光武器颠覆性突破,星链卫星已经不再安全!

域观天下
2024-06-19 10:04:18
多家公司被倒查补税!税务总局回应来了!对企业有什么影响?

多家公司被倒查补税!税务总局回应来了!对企业有什么影响?

学税
2024-06-19 08:25:31
退役太早?34岁巨星大师级表演:3项数据第1,成欧洲杯历史第2人

退役太早?34岁巨星大师级表演:3项数据第1,成欧洲杯历史第2人

侃球熊弟
2024-06-20 02:24:42
吴彦祖父亲节晒与爸爸合影,无P学生照多颗痤疮引热议

吴彦祖父亲节晒与爸爸合影,无P学生照多颗痤疮引热议

葫芦哥爱吐槽
2024-06-18 16:45:19
李莉女士怀抱着无畏的精神,披露国际风云,却不幸陷入网暴漩涡中

李莉女士怀抱着无畏的精神,披露国际风云,却不幸陷入网暴漩涡中

橘色数码
2024-06-06 12:51:20
刚刚!国家队抄底了!

刚刚!国家队抄底了!

中国基金报
2024-06-19 14:33:13
中国女排逃过下下签!奥运抽签令人意外:东道主送自己进死亡之组

中国女排逃过下下签!奥运抽签令人意外:东道主送自己进死亡之组

环太平洋老正太
2024-06-19 20:10:35
笑不活了,猎冰导演称用姚安娜与华为无关,我却笑死在他评论区里

笑不活了,猎冰导演称用姚安娜与华为无关,我却笑死在他评论区里

开玩笑的水母
2024-06-18 18:46:43
好家伙,新《射雕英雄传》开播就差评一片,观众差评理由出奇一致

好家伙,新《射雕英雄传》开播就差评一片,观众差评理由出奇一致

娱乐圈笔娱君
2024-06-18 11:10:45
凌晨3点,商贩与执法城管起争执,西瓜被砸碎一地!当地回应

凌晨3点,商贩与执法城管起争执,西瓜被砸碎一地!当地回应

鲁中晨报
2024-06-20 08:39:07
外媒:因黑山总理迟到,到访的保加利亚总统拒绝等待,两人会晤取消

外媒:因黑山总理迟到,到访的保加利亚总统拒绝等待,两人会晤取消

环球网资讯
2024-06-19 12:45:14
无业大妈扎堆“卖淫”现象,城中村尤其严重,为什么会屡禁不止?

无业大妈扎堆“卖淫”现象,城中村尤其严重,为什么会屡禁不止?

小陆搞笑日常
2024-06-20 07:30:23
尼格买提公开回应:儿子疑已进入小学,首度曝光正面照片

尼格买提公开回应:儿子疑已进入小学,首度曝光正面照片

喜欢历史的阿繁
2024-06-19 07:10:13
生龙活虎!姆巴佩生动形象跟德尚解释受伤过程,国外球迷:笑死了

生龙活虎!姆巴佩生动形象跟德尚解释受伤过程,国外球迷:笑死了

侧身凌空斩
2024-06-20 05:37:13
坐地起价!哈登要求顶薪续约,鲍尔默正式表态,伦纳德苦不堪言

坐地起价!哈登要求顶薪续约,鲍尔默正式表态,伦纳德苦不堪言

体育大朋说
2024-06-19 18:19:20
烟草局回应员工伪造证据后续:官方回应,央媒怒批,评论区炸锅!

烟草局回应员工伪造证据后续:官方回应,央媒怒批,评论区炸锅!

爱意随风起呀
2024-06-20 00:54:21
2024-06-20 09:14:44
IT爱好者小尚
IT爱好者小尚
分享IT教育类信息
630文章数 55关注度
往期回顾 全部

科技要闻

美国AI圈震动! “OpenAI宫斗”核心人物苏茨克维官宣创业

头条要闻

德对华最强硬部长将访华 专家:或向中方传递三层意思

头条要闻

德对华最强硬部长将访华 专家:或向中方传递三层意思

体育要闻

欧洲杯最大的混子,非他莫属

娱乐要闻

黄一鸣“杀疯了” 直播间卖大葱养孩子

财经要闻

茅台大跌,谁的锅?

汽车要闻

双肾格栅变化大/内饰焕新 新一代宝马X3官图发布

态度原创

时尚
房产
旅游
教育
公开课

“T恤”作为夏季的基础款,竟然有这么多种穿法

房产要闻

17.9亿!终于,有民企在三亚大手笔拿地了!周边房价10万+!

旅游要闻

遭遇极端高温天气导致希腊多名游客死亡

教育要闻

微澜月报|2024.5月

公开课

近视只是视力差?小心并发症

无障碍浏览 进入关怀版