系列文章目录

第一章:React从入门到进阶之初识React
第一章:React从入门到进阶之JSX简介
第三章:React从入门到进阶之元素渲染
第四章:React从入门到进阶之JSX虚拟DOM渲染为真实DOM的原理和步骤
第五章:React从入门到进阶之组件化开发及Props属性传值
第六章:React从入门到进阶之state及组件的生命周期
第七章:React从入门到进阶之React事件处理
第八章:React从入门到进阶之React条件渲染
第九章:React从入门到进阶之React中的列表与key
第十章:React从入门到进阶之表单及受控组件和非受控组件
第十一章:React从入门到进阶之组件的状态提升

文章目录

  • 系列文章目录
  • 什么是组件的状态提升
  • 状态提升

什么是组件的状态提升

  • 什么是组件的状态提升呢,为什么需要状态提升?我们先来思考一个问题:

    • 在前面的学习中,我们知道如果一个父组件想要给子组件传递一些值,可以通过props属性的方式进行传递
    • 而如果而子组件想要给父组件传值的话可以通过调用父组件中的方法的方式进行传递(父组件通过props把方法传给子组件,然后子组件在拿到方法后执行该方法并传递参数)
    • 父传子和子传父都有办法实现了,那么如果说兄弟组件之间也想互相传值(或者说共享数据)该如果实现呢,通过props显然是无法实现的。这个时候状态提升就派上用场了
  • 通过上面的分析我们知道了,原来状态提升可以实现兄弟组件间的数据共享。那么到底什么是状态提升,或者说如何实现状态提升,它是如何能让兄弟组件间的数据共享呢
    • 其实很简单,所谓的状态提升就是:在React中将多个组件中需要共享的state向上移动到它们的最近的共同父组件中,便可以实现共享state。
    • 举个简单的例子,比如现在有A、B、C三个组件,其中A是B和C共同的父组件,在B组件中有自己的state管理着B的数据,同样在C组件中也有C自己的state管理着C的数据,那么现在问题是:如果想要B和C之间实现数据共享,那么这个时候就需要把需要共享的state提升至它们共同的父组件A中,然后再通过props分别传递给B和C这样就简单的实现了兄弟组件间的数据共享了。也就是所谓的状态提升
  • 下面我们以一个烧水的案例来展示一下状态提升的运作过程
  • 首先我们创建一个类组件BoilingWater,这个组件里有控制着水温temperture的state,还有一个用于用户输入温度的文本框来模拟温度的变化
  • 然后再添加一个函数组件ShowTemperture,它接收temperture温度作为一个props用于显示当前水温(摄氏度)。

下面我们来完成以下这个小案例的代码

import React from 'react';function ShowTemperture(props){if(props.temperture >= 100){return <p>水烧开了,请享用!<p>}return <p>正在加热中,当前水温是:{props.temperture}℃,请稍后片刻!<p>
}class BoilingWater extends React.Component{constructor(props){super(props);this.state = {temperture:0}}changeTemperture = (e)=>{this.setState({temperture: e.target.value});}render(){return <><ShowTemperture temperture={this.state.temperture}></ShowTemperture><input type='text' value={this.state.temperture} onChange={this.changeTemperture } /></>}
}

以上代码就实现了一个简单的烧水功能。但是目前只能是控制和显示摄氏度,现在我们想要再加一个华氏度输入框,并且还想让两个输入框的数据能够同步共享。

  • 接着上面的例子,我们先从BoilingWater组件中抽离出TempertureInput组件,然后为其添加一个type 的prop,type的值为c或f
const typeNames = {c: '摄氏度',f: '华氏度'
};class TempertureInput extends React.Component {constructor(props) {super(props);this.state = {temperature: ''};}changeTemperture = (e)=>{this.setState({temperture: e.target.value});}render() {const temperture = this.state.temperture;const scale = this.props.type;return (<>{typeNames[scale]}:<input value={temperture}onChange={this.changeTemperture} /></>);}
}

然后我们现在可以修改BoilingWater组件,让它渲染两个独立的温度输入框组件:


class BoilingWater extends React.Component{ render(){return <><ShowTemperture temperture={this.state.temperture}></ShowTemperture><TempertureInput type='c' /><TempertureInput type='f' /></>}
}

上面代码中我们已经添加了两个输入框,但是当我们运行时发现,在一个框中输入温度时,另一个并不会跟着变化,这显然没有实现我们想要的效果,并且我们也不能通过ShowTemperture组件看到实时温度结果,因为ShowTemperture并不知道隐藏在TempertureInput组件内部的当前温度是多少。
接下来我们就用上面提到的状态提升来继续完善我们的小案例

状态提升

  • 到目前为止,两个 TempertureInput 组件均在各自内部的 state 中相互独立地保存着各自的数据。
  • 然而,我们希望两个输入框内的数值彼此能够同步。当我们更新摄氏度输入框内的数值时,华氏度输入框内应当显示转换后的华氏温度,反之亦然。
  • 下面我们将TempertureInput 组件中的state向上移动到它的父组件BoilingWater中去,这样如果BoilingWater组件中拥有了共享的state,它将成为两个温度输入框中当前温度的数据源。它就能够使得两个温度输入框的数值彼此保持一致。由于两个 TempertureInput 组件的 props 均来自共同的父组件 BoilingWater,因此两个输入框中的内容将始终保持一致
  • 继续修改我们的代码
    • 首先我们将 TempertureInput 组件中的 this.state.temperture 替换为 this.props.temperture。现在,我们先假定 this.props.temperature 已经存在,后面我们需要通过 BoilingWater组件将其以props的方式传入
    • 但是我们知道props是只读的不能直接修改。在我们修改代码前temperture 存在于 TempertureInput 组件的 state 中的,这样组件通过调用this.setState() 便可修改它。然而,现在的temperture 是由父组件传入的 prop,TempertureInput 组件便失去了对它的控制权。
    • 这时,我们就需要让自定义的TempertureInput 组件接收 temperture 和 onTempertureChange 这两个来自父组件 BoilingWater的 props,前者(temperture)是用于接收父组件传过来的温度值,后者(onTempertureChange)则是通过父组件通过props传进来的函数进而来修改父组件中的温度值
    • 现在,当 TempertureInput 组件想更新温度时,需调用 this.props.onTempertureChange 来更新它
  • 完善后的代码如下:
const typeNames = {c: '摄氏度',f: '华氏度'
};class TempertureInput extends React.Component {constructor(props) {super(props);this.state = {temperature: ''};}changeTemperture = (e)=>{this.props.onTempertureChange(e.target.value)}render() {const temperture = this.props.temperture;const scale = this.props.type;return (<>{typeNames[scale]}:<input value={temperture}onChange={this.changeTemperture} /></>);}
}

接下来,我们继续完善我们的父组件BoilingWater

  • 在父组件中我们hui会把当前输入的temperture和type保存在组件内部的state中。这个 state 就是从两个输入框组件中“提升”而来的,并且它将用作两个输入框组件的共同“数据源”。这是我们为了渲染两个输入框所需要的所有数据的最小表示。
  • 现在当我们在摄氏度输入框中输入100时,BoilingWater中的state将会是{temperture: 100, type:‘c’},如果我们在华氏度中输入212时,BoilingWater中的state将会是{temperture: 212, type:‘f’}
  • 然后我们就可以根据当前的温度类型和当前的温度值换算出另一个类型的温度了。
  • 由于两个输入框中的数值都是由同一个 state 计算而来,因此它们始终保持同步,这样就实现了兄弟组件间的数据共享了。

BoilingWater组件完整代码如下:

class BoilingWaterextends React.Component {constructor(props) {super(props);   this.state = {temperture: '', type: 'c'};}handleCelsiusChange = (temperture) => {this.setState({type: 'c', temperture});}handleFahrenheitChange = (temperture) => {this.setState({type: 'f', temperture});}render() {const type = this.state.type;const temperture = this.state.temperture;const celsius = type === 'f' ? (temperture - 32) * 5 / 9 : temperture;const fahrenheit = type === 'c' ? (temperture * 9 / 5) + 32 : temperture;return (<div><ShowTemperture temperture={celsius}></ShowTemperture><TempertureInput type='c' temperture={celsius} onTempertureChange={this.handleCelsiusChange} /><TempertureInput type='f' temperture={fahrenheit} onTempertureChange={this.handleFahrenheitChange}/>           </div>);}
}

到此,我们就完成了我们的小案例,现在无论我们编辑哪个输入框中的内容,BoilingWater组件中的 this.state.temperture 和 this.state.type均会被更新。其中一个输入框保留用户的输入并取值,另一个输入框始终基于这个值显示转换后的结果。
让我们来重新梳理一下当你对输入框内容进行编辑时会发生些什么:

  • React 会调用 DOM 中 < input> 的 onChange 方法。在本实例中,它是 TempertureInput 组件的 changeTemperture方法
  • TempertureInput 组件中的 changeTemperture方法会调用 this.props.onTemperatureChange(),并传入新输入的值作为参数。其 props 诸如 onTempertureChange 之类,均由父组件 BoilingWater提供
  • 起初渲染时,用于摄氏度输入的子组件 TempertureInput 中的 onTemperatureChange 方法与 BoilingWater组件中的 handleCelsiusChange 方法相同,而,用于华氏度输入的子组件 TempertureInput 中的 onTemperatureChange 方法与 BoilingWater组件中的 handleFahrenheitChange 方法相同。因此,无论哪个输入框被编辑都会调用 BoilingWater组件中对应的方法。
  • 在这些方法内部,BoilingWater组件通过使用新的输入值与当前输入框对应的温度计量单位来调用 this.setState() 进而请求 React 重新渲染自己本身。
  • React 调用 BoilingWater组件的 render 方法得到组件的 UI 呈现。温度转换在这时进行,两个输入框中的数值通过当前输入温度和其计量单位来重新计算获得。
  • React 使用 BoilingWater组件提供的新 props 分别调用两个 TempertureInput 子组件的 render 方法来获取子组件的 UI 呈现。
  • React 调用 ShowTemperture组件,并将摄氏温度值以组件 props 方式传入。
  • React DOM 根据输入值匹配水是否沸腾,并将结果更新至 DOM。我们刚刚编辑的输入框接收其当前值,另一个输入框内容更新为转换后的温度值。

本章内容就介绍到这里
下一章节中我们将给大家继续讲解React中的组合

web前端高级React - React从入门到进阶之组件的状态提升相关推荐

  1. web前端高级React - React从入门到进阶之高阶组件

    第二部分:React进阶 系列文章目录 第一章:React从入门到进阶之初识React 第一章:React从入门到进阶之JSX简介 第三章:React从入门到进阶之元素渲染 第四章:React从入门到 ...

  2. web前端高级React - React从入门到进阶之组件的懒加载及上下文Context

    第二部分:React进阶 系列文章目录 第一章:React从入门到进阶之初识React 第一章:React从入门到进阶之JSX简介 第三章:React从入门到进阶之元素渲染 第四章:React从入门到 ...

  3. web前端高级React - React从入门到进阶之Render Props

    第二部分:React进阶 系列文章目录 第一章:React从入门到进阶之初识React 第一章:React从入门到进阶之JSX简介 第三章:React从入门到进阶之元素渲染 第四章:React从入门到 ...

  4. web前端高级React - React从入门到进阶之初识React

    第一部分:React入门 系列文章目录 第一章:React从入门到进阶之初识React 第一章:React从入门到进阶之JSX简介 第三章:React从入门到进阶之元素渲染 第四章:React从入门到 ...

  5. web前端高级React - React从入门到进阶之React条件渲染

    系列文章目录 第一章:React从入门到进阶之初识React 第一章:React从入门到进阶之JSX简介 第三章:React从入门到进阶之元素渲染 第四章:React从入门到进阶之JSX虚拟DOM渲染 ...

  6. react组件卸载调用的方法_好程序员web前端培训分享React学习笔记(三)

    好程序员web前端培训分享React学习笔记(三),组件的生命周期 React中组件也有生命周期,也就是说也有很多钩子函数供我们使用, 组件的生命周期,我们会分为四个阶段,初始化.运行中.销毁.错误处 ...

  7. web前端高级JavaScript - 彻底掌握基于HTTP网络层的“前端性能优化”

    彻底掌握基于HTTP网络层的 "前端性能优化" 产品性能优化方案 HTTP网络层优化 代码编译层优化 webpack 代码运行层优化 html/css javascript vue ...

  8. web前端技术(二)之动画进阶

    web前端技术(二)之动画进阶 目录 web前端技术(二)之动画进阶 前言 一.web前端动画是什么 二.2D转换标签(transforms) 1. translate() 2.rotate() 3. ...

  9. web前端 vue、react、angular三大框架对比 与jquery的对比

    前端当前最火的三大框架当属vue.react以及angular了. 但是在做项目的时候,我们怎么去选择呢?  这里做一个比较,希望大家可以有一个比较清晰的认识. vue与react vue和react ...

最新文章

  1. Archlinux 下的 VMWare Workstation 维护笔记
  2. git恢复到上次提交
  3. NetBeans IDE 7.0 Beta 发布
  4. linux-文件目录类
  5. Java的token解决方案,SpringMVC后台token防重复提交解决方案
  6. Vue.js开发记录--用watch监听对象中属性的变化
  7. Centos安装MysqlServer与MysqlWorkbench
  8. 局部变量与全局变量同名时如何在局部变量的作用范围内访问全局变量?
  9. Java的环境变量配置
  10. 盛大易宝只是陈天桥的梦而已
  11. 【报告分享】2021年中国网络文学出海报告-艾瑞咨询(附下载)
  12. 安全提示:勒索病毒漏洞与CPU漏洞务必小心
  13. 推荐Arduino更深入学习:《新概念51单片机C语言教程》-郭天祥(文章内含学习资料供下载)
  14. 2020年1024程序员节,成为CSDN博客专家
  15. 批量安装windows系统补丁包
  16. 微软新版edge浏览器如何开启画中画模式 (微软新版edge)
  17. 用AOMEI Partition Assistant制作PE 启动盘
  18. 日志分析篇---Linux日志分析
  19. 一定要理解的两种常见软件开发体系结构(CS/BS结构)的区别!!!
  20. RTF(富文本格式)与HTML(超文本标记语言)的区别?

热门文章

  1. 利用串口服务器WiFi转RS485组网
  2. linux环境下用jmeter 5.4.3进行性能测试
  3. python微信昵称乱码
  4. CPU、MPU、MCU、SOC的理解
  5. 核算现金折扣的方法有3种:总价法、净价法和备抵法 介绍
  6. Python 判断今天是今年的第几天?
  7. 一起写个Dubbo——1. 一个最简单的实现
  8. SDNUOJ 1213.金额的中文大写
  9. 室外排水设计规范_房屋建筑工程现行规范标准目录汇编(2020版)—给排水—图集篇...
  10. 【原创】如何判断三条边能否构造出一个三角形