React 回忆录(四)React 中的状态管理

React 回忆录(四)React 中的状态管理

大家好,又见面了,我是你们的朋友全栈君。

Hi 各位,欢迎来到 React 回忆录!? 在上一章中,我介绍了使用 React 渲染界面元素的方法,以及在这个过程中蕴含的“组件化”想想。在本章中,我们将把目光聚焦于 React 组件内部的状态管理,去认识或重新思考以下三个核心概念:

  1. propsstate
  2. 函数组件
  3. 类组件

让我们开始吧! ?

01. React 中的数据

站在“组件”的角度上,React 把应用中流动的数据分为两种类型:

  1. 不可更改内容,但可以单向跨组件传递的 props
  2. 可以更改内容,但不能跨组件传递的 state

进一步说,propsstate 的区别在于,props 是外部的,并且被任何渲染这个组件的代码所控制。而 state 则是内部的,并且被组件自身所控制。

非计算机专业的初学者经常困惑
props
state 在名称与含义上的关联,其实大可不必在意,他们本质上只是
数据的别称,只是在 React 中,它们被各自赋予了特殊的限制或能力。

你可以通过组件上的 props 属性,像在 HTML 中传递属性一样,将你想要传递的任何数据传递给子组件,所有的属性都会被存储在子组件(类组件)的 this.props 对象中。

function Parent(props) {
    return <Child name={"Tom"} />
}

function Child(props) {
    return <span>(props.name)</span>
}

02. 函数组件

我们之前提到过,React 使用组件渲染视图提升性能,而组件即是一个函数,可以用一个公式来简洁的表示其功用:f(数据) => UI。到这里我想你应该注意到了,为什么我们说 React 并不是一个大型的 MVC (或 MVVM)框架,因为 React 只负责视图层(View)的渲染,其他的事情将由 React 生态中的其他工具来完成。

话说回来,对于 React 组件而言,最简单的一种形式莫过于函数组件了,它充分展现了 React 的哲学,一次只做一件事组件化数据驱动UI

函数组件又称为“无状态组件”,“受控组件”或“木偶组件”,因为函数组件只负责接收 props 并返回 UI,它自身并不能拥有可改变的数据,在真实的 React 应用开发场景下,我们经常尽可能的使用函数组件,将整个应用的 UI 拆分成尽可能小的视觉单元。

这是因为函数组件是非常直观的,它接收属性返回元素,内部逻辑清晰明确,而且更重要的是,函数组件内没有 this 关键字,因此你永远不用担心烦人的“this上下文问题”。

记住:如果你的组件不需要追踪内部状态,尽量使用函数组件。


03. 类组件

和函数组件相对应的,便是“类组件”了,类似的,它也被称为“有状态组件”,“非受控组件”和“容器组件”。这里需要注意,虽然我们按照代码的形式为两种类型的组件命名,但这并不严谨,因为在 JavaScript 中,“类”也是函数。

不同于函数组件,类组件拥有着可以更改的内部数据 — state。它最终影响着页面的渲染情况,而且 state 可以被组件在任何时刻在内部修改。通常的时刻时用户与界面发生交互的时候。

由于 React 把变化的数据封装在组件内部,并坚持单向数据流的原则。我们有了高度抽象的 UI 组件,并封装复杂的业务逻辑。这使得我们可以通过构建,组合一系列小组件开发出大型应用。

那么应该如何向类组件添加 state 呢?很简单,我们所要做的只是在类组件内部添加一个 state 属性,state 属性是一个对象。这个对象代表了组件的状态,对象的每一个属性名都代表组件的一个特定的状态,下面是具体的代码:

import React from "react"

class Parent extends React.Component {
    state = {
        name: "Eliot",
    }
    
    render() {
        return <p>{this.state.name}</p>
    }
}

React 使我们迫使大脑关注两个重要的部分:

  1. 组件看起来是什么样?
  2. 组件当前的状态是什么?

通过让组件管理自己的状态,任何时候状态的变更都会令 React 自动更新相应的页面部分。这便是使用 React 构建组件的主要优势之一:当页面需要重新渲染时,我们仅仅需要思考的是如何更改状态。我们不必跟踪页面的哪些部分需要更改,不需要决定如何有效的重新呈现页面,React 自会比较先前的输出和新的输出,决定什么应该发生改变,并为我们做出决定。而这个确定之前改变了什么和现在应该新输出什么的过程有一个专门的名词,叫做 Reconciliation


04. 修改 state

你应该还记得类组件与函数组件最大的不同在于类组件自身拥有可以改变内部数据的能力。那么如何行使这一能力呢?和直觉不同,要做到这一点,你需要使用 React 提供的专门的 API:this.setState()

你有两种方式使用该 API:

  1. 设置对象参数;
  2. 设置函数参数;

让我们先来看看第一种:

this.setState({
    name: "Tom"
})

React 会自动合并对 state 的改变。而有时,你的组件需要一个新的 state ,而这个 state 的变化又依赖于旧的 state 值,每当这种时候,你就该使用第二种 API 调用方式:

this.setState((prevState) => ({
    name: "mr." + prevState.name
}))

讲到这里你可能会感到奇怪,只是更新 state 而已,为什么还需要调用一个专门的 API?我们直接修改之前定义的 state 对象不就好了吗?之所以这样设计的原因是,组件内 state 的变化不仅仅是对象属性值发生变化那么简单,它还需要驱动整个 UI 进行重新渲染,因此 this.setState() 这个 API 被调用时实际上做了两件事:

  1. 修改 state 对象;
  2. 驱动组件重新渲染;

如果你对 React 有一定研究,你可能会质疑我以上所罗列的两点并不精确,的确如此,小小的 this.setState() API 其实内部还有很多细节值得注意,例如,当调用 this.setState() 时并不会立即改变 state 的值,也当然不会立即重新渲染组件。例如,当以对象为参数调用 this.setState() API 时,尽管内部重复为数据赋值,最终的数据也只保留最后一次更改的结果。

不过幸好,这些略显古怪的状态早有前人为我们做了详尽的解释,如果你感兴趣,请点击下方链接查询更多的信息:


05. 控制组件

当你在 Web 应用中使用表单时,这个表单的数据被存储于相应的 DOM 节点内部,但正如我们之前提到的,React 的整个关键点就在于如何高效的管理应用内的状态。所以虽然表单的数据被存储于 DOM 中,React 依然可以对它进行状态管理。

而管理的方式即是使用“控制组件”。简单而言,“控制组件”会渲染出一个表单,但是将表单所需的所有真实数据作为 state 存储于组件内部,而不是 DOM 中。

之所以被称为“控制组件”的原因也即在于此,“控制组件”控制着组件内的表单数据,因此,唯一更新表单数据的方式就是更新组件内部对应的 state 值。

import React as "react"

class Input extends React.Component {
    state = {
        value: "enter something...",
    }
    
    handleClick: (e) => {
        this.setState({value: e.target.value})
    }
    
    render() {
        <input value={this.state.value} onKeyup={this.handleClick} />
    }
}

可以看到,我们使用 handleClick 方法响应用户每一次键盘敲击以即时更新表单状态,这样做不仅天然的支持了即时的输入验证,还允许你有条件的禁止或点亮表单按钮。


06. 小结

这一章我们介绍了 React 的两种数据形式:stateprops,并且介绍了 React 组件的两种形式:函数组件类组件,希望格外有所收获,如果有任何问题或建议,也欢迎各位在评论区内留言,下一章见 ?

PS:?如果你对该专题感兴趣,别忘了订阅本专栏,确保及时收到更新通知。记得点击下方?的各个按钮,让我知道你认可我的付出,这是激励我持续产出的动力和源泉 ?。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/107410.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 零基础学Java(13)方法参数[通俗易懂]

    零基础学Java(13)方法参数[通俗易懂]前言首先回顾一下在程序设计语言中关于如何将参数传递给方法的一些专业术语。按值调用表示方法接收的是调用者提供的值。而按引调用表示方法接收的是调用者提供的变量地址。方法可以修改按引用传递的变量的值,而不

  • dhcp option 82 接入交换机_dhcpoption怎么配置

    dhcp option 82 接入交换机_dhcpoption怎么配置Option82应用场景在该场景下,临时接入者可以在不安装认证客户端的情况下,直接访问Internet资源,但是不能访问学校、企业、政府单位的内网,适用于各种会务、学术交流、临时参观等应用场景,正式员工可以在会议区通过认证接入到内网。为了实现该场景,我们首先要对神州数码网络交换机产品的DHCPOption82功能进行描述。Option82相关技术Option82功能介绍  DH…

    2022年10月16日
  • GloVe模型_nerlove模型

    GloVe模型_nerlove模型系列目录(系列更新中)第二讲cs224n系列之word2vec&amp;amp;amp;amp;amp;amp;词向量word2vec进阶之skim-gram和CBOW模型(HierarchicalSoftmax、NegativeSampling)第三讲cs224n系列之skip-pram优化&amp;amp;amp;amp;amp;amp;GlobalVectorbyManning&amp;amp;amp;amp;amp;amp;

  • SwipeRefreshLayout 与 CoordinatorLayout 嵌套刷新[通俗易懂]

    SwipeRefreshLayout 与 CoordinatorLayout 嵌套刷新[通俗易懂]SwipeRefreshLayout与CoordinatorLayout嵌套刷新 1.动态设置SwipeRefreshLayout的是否可以刷新setEnable(booleanisEnable); 2.设置SwipRefreshLayout刷新图标的位置setProgressViewOffset(true,-20,100);首先看SwipeRefreshLa

  • goland 2021 激活码【注册码】[通俗易懂]

    goland 2021 激活码【注册码】,https://javaforall.cn/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

  • WPA3在2018年为无线安全添砖加瓦

    WPA3在2018年为无线安全添砖加瓦Wi-FiAllianceAnnouncesWPA3,theSuccessortoWi-Fi’sWPA2SecurityProtocolTheWi-FiAlliance–comprising15majorsponsormembers(includingApple,Cisco,Dell,Intel,Microsoft,Qualcomman

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号