React中文文档之Lifting State Up

2023-11-05

Lifting State Up - 提升状态
经常的,几个组件需要映射相同的数据改变。我们推荐提升共享的state状态到它们最近的公共祖先元素。让我们看看这是如何实现的。
在这个章节,我们将创建一个温度计算器,计算在一个给定的温度,水是否会沸腾。
我们以一个叫做 'BoilingVerdict' 的组件开始。它接收 'celsius' 温度作为一个prop,并且打印是否足够使水非常。
		function BoilingVerdict(props) {
			if (props.celsius >= 100) {
				return <p>The water would boil.</p>;
			} else {
				return <p>The water would not boil.</p>;
			}
		}

接下来,我们创建一个叫做 'Calculator' 的组件。它渲染一个 <input> ,让你输入温度,并使用 'this.state.value' 来保持它的值。
另外,它根据当前输入的值来渲染 'BoilingVerdict' 。
		class Calculator extends React.Component {
			constructor(props) {
				super(props);
				this.handleChange = this.handleChange.bind(this);
				this.state = {value: ''};
			}
			handleChange(e) {
				this.setState({value: e.target.value});
			}
			render() {
				const value = this.state.value;
				return (
				    <fieldset>
				        <legend>Enter temperature in Celsius:</legend>
				        <input
				          	value={value}
				          	onChange={this.handleChange} />
				        <BoilingVerdict
				          	celsius={parseFloat(value)} />
				    </fieldset>
				);	
			}
		}

添加第二个输入框
我们的新需求是:除了 'Celsius' 输入框,我们提供一个 'Fahrenheit' 输入框,并且它们保持同步。
我们可以通过从 'Calculator' 提取一个 'TemperatureInput' 组件来开始。我们将添加一个新的 'scale' prop给 'TemperatureInput' 组件,'scale' 可以是 'c' 或 'f':
		const scaleNames = {
			c: 'Celsius',
			f: 'Fahrenheit'
		};
		class TemperatureInput extends React.Component {
			constructor(props) {
				super(props);
				this.handleChange = this.handleChange.bind(this);
				this.state = {value: ''};
			}
			handleChange(e) {
				this.setState({value: e.target.value});
			}
			render() {
				const value = this.state.value;
				const scale = this.props.scale;
				return (
				    <fieldset>
				        <legend>Enter temperature in {scaleNames[scale]}:</legend>
				        <input value={value}
				          	onChange={this.handleChange} />
				    </fieldset>
				);	
			}
		}


现在让我们来改变 Calculator 来渲染2个独立的温度输入框:
		class Calculator extends React.Component {
			render() {
				return (
					<div>
						<TemperatureInput scale="c" />
						<TemperatureInput scale="f" />
					</div>
				);
			}
		}

现在我们已经有2个输入框了,但是当你在它们中的一个输入温度时,另一个不更新。这与我们的需求矛盾:我们想要2者同步。
从 'Calculator' 组件中,我们也无法展示 'BoilingVerdict'。'Calculator' 不知道当前的温度,因为它隐藏在 'TemperatureInput' 的内部。


提升state状态
首先,我们写2个函数,从 'Celsius' 转换为 'Fahrenheit',然后反过来。
		function toCelsius(fahrenheit) {
			return (fahrenheit - 32) * 5 / 9;
		}
		function toFahrenheit(celsius) {
			return (celsius * 9 / 5) + 32;
		}

这2个函数转换数字。我们写另外一个函数,接收一个字符串 'value' 和一个转换函数名作为参数,并返回一个字符串。我们使用它来计算一个输入框的值,基于另一个输入框。
当传入一个无效的 'value',返回一个空字符串,并保证输出到第三位小数。
		function tryConvert(value, convert) {
			const input = parseFloat(value);	
			if (Number.isNaN(input)) {
				return '';	
			}
			const output = convert(input);
			const rounded = Math.round(output * 1000) / 1000;
			return rounded.toString();
		}
例如,tryConvert('abc', toCelsius) 返回一个空字符串,tryConvert('10.22', toFahrenheit)返回 '50.396'
接着,我们从 'TemperatureInput' 组件中,移除 state 状态。
替代的,'TemperatureInput' 组件通过props接收 'value' 和 'onChange' 处理器(之前value是通过 state 来接收):
		class TemperatureInput extends React.Component {
			constructor(props) {
				super(props);
				this.handleChange = this.handleChange.bind(this);
			}
			handleChange(e) {
				this.setState({value: e.target.value});
			}
			render() {
				const value = this.props.value;
				const scale = this.props.scale;
				return (
				    <fieldset>
				        <legend>Enter temperature in {scaleNames[scale]}:</legend>
				        <input value={value}
				          	onChange={this.handleChange} />
				    </fieldset>
				);	
			}
		}

如果几个组件需要访问同样的state,这是一个信息,state应该被提升到它们最近的公共祖先上来替代。在我们的案例中,公共祖先是 'Calculator'。我们将存储当前的 'value' 和 'scale' 到它的 state。
我们可能已经存在了两个输入框的值,但是它原来是没有必要的。存储最近改变的输入框的值和它代表的 'scale' 就足够了。之后,我们可以根据当前的 'value' 和 'scale' 来推断出另一个输入框的值。
2个输入框保持同步,因为它们的值可以从相同的state来计算的到:
		class Calculator extends React.component {
			constructor(props) {
				super(props);
				this.handleCelsiusChange = this.handleCelsiusChange.bind(this);
				this.handleFahrenheitChange = this.handleFahrenheitChange.bind(this);
				this.state = {value: '', scale: 'c'};
			}
			handleCelsiusChange(value) {
				this.setState({scale: 'c', value});
			}
			handleFahrenheitChange(value) {
				this.setState({scale: 'f', value});
			}
			render() {
				const scale = this.state.scale;
				const value = this.state.value;
				const celsius = scale === 'f' ? tryConvert(value, toCelsius) : value;
				const fahrenheit = scale === 'c' ? tryConvert(value, toFahrenheit) : value;
				return (
			      <div>
				        <TemperatureInput
				         	scale="c"
				          	value={celsius}
				          	onChange={this.handleCelsiusChange} />
				        <TemperatureInput
				          	scale="f"
				          	value={fahrenheit}
				          	onChange={this.handleFahrenheitChange} />
				        <BoilingVerdict
				          	celsius={parseFloat(celsius)} />
			      </div>
				);
			}
		}

现在,不管你编辑哪个输入框,'Calculator'组件中的 'this.state.value' 和 'this.state.scale' 都会更新。任何用户输入保留下来,一个输入框获取到用户输入到值,另一个输入框基于它,总是重新计算。


课程总结
在React应用中,任何数据都应该有一个单一的真实数据来源。通常的,为了渲染,state是第一个被添加到组件中。之后,如果其他组件也需要它,可以提升state到它们最近的祖先元素上。替代尝试同步不同组件间的state,我们应该依靠的是 'top-down data flow - 自上而下的数据流'
相比于 'two-way binding approaches - 双向绑定方法',提升state状态,涉及写更多的 'boilerplate - 样板文件' 代码,但是它有一个好处,花费更少的工作查找和杜绝bug。因为任何state存在于一些组件,组件单独可以修改它,这样bugs的表面范围就大大减少了。另外,你可以实现任何自定义逻辑来拒绝或转换用户输入。
如果一些变量,通过 'props' 和 'state' 都可以获取,最好不要使用 'state',而应该用 'props'。例如:我们进存储最后编辑的 'value' 和 它的 'scale',而不存储 'celsiusValue' 和 'fahrenheitValue'。在 'rend()' 方法中通过它们,另一个输入框的值总会被计算。这可以让我们清楚或应用于其他字段,而不会丢失用户输入的任何精度
当你在UI中发现一些错误,你可以使用 'React开发者工具' ,来检查 props,并移动树形结构,直到找到组件响应的state更新。这让你可以在源码中追踪bug
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

React中文文档之Lifting State Up 的相关文章

随机推荐

  • 操作系统进程管理相关习题

    一 选择题 从静态角度上看 进程是有 A B C 三部分组成 其中 C 是进程存在的唯一标志 当几个进程共享 A 时 A 应当是可重入代码 A B C 1 JCB 2 PCB 3 DCB 4 FCB 5 程序段 6 数据段 7 I O缓冲区
  • 基于OpenCv的人脸识别

    OpenCV 是一个开源的计算机视觉库 它支持多种编程语言 包括 C Python 等 它包含了很多计算机视觉算法和工具 其中包括人脸识别 人脸识别的基本思路是 首先从图像或视频中检测出人脸的位置 然后对人脸进行特征提取 最后根据这些特征来
  • Vue npm run dev 时提示“sh: 1: webpack-dev-server: not found“

    记录自用 在ubuntu下运行项目的时候出现如下问题 经过查找 发现应该是缺少部分模块的原因 通过执行 npm install 成功解决问题
  • eglSwapBuffers

    一般性嵌入式平台 利用双缓冲进行Swap的时候 Display和Surface进行实际意义上的地址交换 来实现eglSwapBuffers的标准 如上图的右侧所示 上图的左侧表示 单缓冲Framebuffer的形式 Surface永远都在后
  • GD32F103搭建工程记录: cannot open source input file “RTE_Components.h“: No such file or director

    搭建兆亿的 GDF103C8T6的工程的时候提示 报错 cannot open source input file RTE Components h No such file or directory 工程文件是 仿照stm32 去搭建的
  • 预置APK到android系统中(带源码/不带源码)

    一 如何将带源码的APK预置进系统 1 首先将app代码放在源码中 1 1 可以放在vendor 目录下自己项目的package app 下面 1 2 可以放在vendor google partner gms apps 或者 vendor
  • 服务器数据库查看版本信息失败,查看服务器上的数据库版本

    查看服务器上的数据库版本 内容精选 换一换 升级PostgreSQL引擎大版本 能让您享受到PostgreSQL新版本带来的功能 性能 安全的提升 但大版本升级可能存在向后不兼容的数据变更 可能导致现有业务运行不兼容 因此需要用户使用目标版
  • 程序中断方式

    系统设置程序中断的目的就是能让系统处理更高等级的任务 比如紧急事件 对系统有改动的更高权限的任务 因为CPU 是计算机中处理任务的核心 程序中断在CPU中设立 外设和程序中端分别是由中端控制器和程序内置的中断服务程序配合操作系统来决定 使操
  • 计算机硬件acc作用,累加器A的主要作用是什么_一文解析累加器a和acc的区别

    累加器简介 在中央处理器中 累加器 accumulator 是一种寄存器 用来储存计算产生的中间结果 如果没有像累加器这样的寄存器 那么在每次计算 加法 乘法 移位等等 后就必须要把结果写回到内存 也许马上就得读回来 然而存取主存的速度是比
  • 【微信小程序】微信小程序支付、微信小程序webview引入H5实现支付等

    最近有个需要由于H5页面需要嵌套在微信小程序里面 所以H5的支付在小程序里面就行不通了 不过我看社区里面说的测试环境微信小程序webview引入H5是可以实现调取H5支付功能的 线上则调不起来 时间紧迫 咱也不敢尝试啊 只能另辟蹊径了 哈哈
  • vs2013+qt5.9.5+vsaddin安装配置

    一 下载地址 Qt下载地址 https mirrors tuna tsinghua edu cn qt archive qt 5 9 5 9 5 qt opensource windows x86 5 9 5 exehttps mirror
  • 【安全开发】C/C++安全编码规范

    C本质上是不安全的编程语言 例如如果不谨慎使用的话 其大多数标准的字符串库函数有可能被用来进行缓冲区攻击或者格式字符串攻击 但是 由于其灵活性 快速和相对容易掌握 它是一个广泛使用的编程语言 下面是针对开发安全的C语言程序的一些规范 1 1
  • windows11百度网盘下载,win11iso镜像百度云下载

    windows11百度网盘下载 win11iso镜像百度云 windows11百度网盘下载 win11iso镜像百度云链接 https pan baidu com s 1r96WDwsDURdrRt1nl Z0PQ 提取码 6666 上面是
  • 在vant组件下阻止手机自带键盘弹起

    废话 van field输入框伴随着小键盘的弹起 但是在已经定义了的van popup中 小键盘的弹起显得多余 尤其在地区 籍贯等的选择上 所以利用 focus 在获取焦点的时候进行阻止 代码
  • 局域网配置网站DNS服务器的安装

    小提示 要想成功部署DNS服务 运行Windows Serve 2003的计算机中必须拥有一个静态IP地址 只有这样才能让DNS客户端定位DNS服务器 另外如果希望该DNS服务器能够解析Internet上的域名 还需保证该DNS服务器能正常
  • STM32单片机示例:多个定时器级联使用

    文章目录 目的 基础说明 关键配置与代码 示例链接 目的 有些情况下会遇到单片机的定时器位数不够用 这时候可以使用低定时器级联的方式来处理 这里将对此做个示例说明 基础说明 这里说的定时器级联是指一个定时器正常计数工作 然后在发生溢出时发送
  • PYthon 转换HTML到Text纯文本

    今天项目需要将HTML转换为纯文本 去网上搜了一下 发现Python果然是神通广大 无所不能 方法是五花八门 拿今天亲自试的两个方法举例 以方便后人 方法一 1 安装nltk 可以去pipy装 注 需要依赖以下包 numpy PyYAML
  • AT24C02的使用说明和完整代码-51单片机

    AT24C02的使用说明和完整代码 51单片机 简述 at24c02为存储器芯片 可以使用单片机将数据存入其中 同时也可以任意读取 at24c02的原理及使用方法在其说明资料中已有充分的讲述 本篇仅对其使用的关键步骤进行罗列 以及说明一下具
  • MySQL主从复制的实现

    MySQL主从复制的理解图 MySQL Replication原理 主从复制 也称 AB 复制 允许将来自一个MySQL数据库服务器 主服务器 的数据复制到一个或多个MySQL数据库服务器 从服务器 复制是异步的 从站不需要永久连接以接收来
  • React中文文档之Lifting State Up

    Lifting State Up 提升状态 经常的 几个组件需要映射相同的数据改变 我们推荐提升共享的state状态到它们最近的公共祖先元素 让我们看看这是如何实现的 在这个章节 我们将创建一个温度计算器 计算在一个给定的温度 水是否会沸腾