当前位置: 首页 > 编程日记 > 正文

React文档 state and lifecycle

状态和生命周期

这篇介绍 React 组件中状态和声明周期的概念。详情可以查看API参考 。

思考前一部分中时钟的例子。渲染元素中,我们仅学习了一种更新 UI 的方式。调用 ReactDOM.render() 改变渲染后的输出。

function tick() {const element = (<div><h1>Hello, world!</h1><h2>It is {new Date().toLocaleTimeString()}.</h2></div>);ReactDOM.render(element,document.getElementById('root'));
}

在线尝试

这部分,我们学习如何编写真正可复用的封装 Clock 组件。 它会设置自己的计时器每秒更新自己。

我们从封装 时钟的外层开始:

function Clock(props) {return (<div><h1>Hello, world!</h1><h2>It is {props.date.toLocaleTimeString()}.</h2></div>);
}function tick() {ReactDOM.render(<Clock date={new Date()} />,document.getElementById('root'));
}setInterval(tick, 1000)

[在线尝试]()

但这个忽视了一个最重要的需求: Clock 创建一个计时器且每秒更新自身 UI 应该是一个 Clock 的细节实现。

理想情况下我们写一次让 Clock 更新自身:

ReactDOM.render(<Clock />,document.getElementById('root')
);

实现这一需求我们需要给 Clock 组件添加 "state".

State 很类似 props, 不同的是它完全私有由组件控制。

函数转化为类

转化一个类似 Clock 的函数组件为类组件需要五步:

  1. 创建一个 [ES6标准的类](), 名称不变,继承 React.Component.
  2. 重写 render()方法。
  3. 函数的祖逖移到 render() 方法中。
  4. render() 方法体重使用 this.props替换 props
  5. 删除空的函数声明。
class Clock extends React.Component {render() {return (<div><h1>Hello, world!</h1><h2>It is {this.props.date.toLocaleTimeString()}.</h2></div>);}
}

[在线尝试]()

函数组件定义的 Clock 现在由类组件定义。

render() 方法会在每次更新时调用,但是只要我们渲染 <Clock /> 到同样的 DOM 节点,就会使用 Clock 类的单一实例。这让我们可以使用如 local state 和 lifecycle 钩子等额外的特性。

为类添加本地状态

三步把 date 从 props 移动到 state:

  1. render() 方法中使用 this.state.date 替换 this.props.date
class Clock extends React.Component {render() {return (<div><h1>Hello, world!</h1><h2>It is {this.state.date.toLocaleTimeString()}.</h2></div>);}
}
  1. 添加一个[类构造器]()来分管 this.state 的初始化:
class Clock extends React.Component {constructor(props) {super(props);this.state = {date: new Date()};}render() {return (<div><h1>Hello, world!</h1><h2>It is {this.state.date.toLocaleTimeString()}.</h2></div>);}
}

注意我们传递 props 到基础构造器:

  construct(props) {super(props);this.state = {date: new Date()};}

类组件总是通过 props 调用基础构造器。

  1. 移除<Clock /> 元素中的 date props :
  ReactDOM.render(<Clock />,document.getElementById('root'));

待会我们在将计时器代码回写到 组件本身。

结果如下:

class Clock extends React.Component {constructor(props) {super(props);this.state = {date: new Date()};}render() {return (<div><h1>Hello, world!</h1><h2>It is {this.state.date.toLocaleTimeString()}.</h2></div>);}
}
ReactDOM.render(<Clock />,document.getElementById('root')
);

[在线尝试]()

下面,我们编写 Clock 设置他自己的计时器每秒更新自身。

为类添加声明周期方法

多个组件的应用中,当组件销毁时释放组件占用的资源非常重要。

我们想 [设置一个计时器]() 无论何时 Clock 第一次被渲染到 DOM. React 中称之为 ”mounting".

我们也想 [清楚一个计时器]() 无论何时 Clock 被DOM 移除。 React 中称之为 “unmounting".

当组件 mounts 和 unmounts 时我们可以在组件类声明特殊的方法来运行。

class Clock extends React.Component {constructor(props) {super(props);this.state = {date: new Date()};}componentDidMount() {}componentWillMount() {}render() {return (<div><h1>Hello, world!</h1><h2>It is {this.state.date.toLocaleTimeString()}.</h2></div>);}
}

这些方法称为 "lifecycle hooks(生命周期钩子)".

componentDidMount() 钩子在组件输出渲染至DOM 后运行。这个位置很适合建立一个计时器:

  componentDidMount() {this.timerID = setInterval(() => this.tick(), 1000);}

注意我们如何正确的将 计时器 ID 保存到 this.

当 React 设置 this.props this.state 有了特别的含义,你可以随意为类手动添加额外字段,如果你需要保存一些不参与数据流(比如 timerID)。

我们在 componentWillUnmount() 生命周期钩子函数中去掉 计时器。

  componentWillUnmount() {clearInterval(this.timerID);}

最后我们,实现一个称为 tick() 的方法实现 Clock 组件每秒运行。

这会用到 this.setState() 来调度更新组件的本地状态:

class Clock extends React.Component {constructor(props) {super(props);this.state = {date: new Date()};}componentDidMount() {this.timerID = setInterval(() => this.tick(), 1000);}componentWillUnmount() {clearInterval(this.timerID);}tick() {this.setState({date: new Date()});}render() {return (<div><h1>Hello, world!</h1><h2>It is {this.state.date.toLocaleTimeString()}.</h2></div>);}
}ReactDOM.render(<Clock />,document.getElementById('root')
);

在线尝试

现在时钟按秒运行。

快速的回顾下发生了什么还有方法调用顺序:

  1. <Clock /> 传给 ReactDOM.render(), React 调用Clock 组件的构造器。从 Clock 需要显示当前时间,它通过包含当前时间的对象初始化 this.state。稍后更新 state.
  2. React 调用 Clock 组件的 render() 方法,知道应该在屏幕上显示什么。React 之后更新 DOM 来匹配 Clock 的渲染后输出。
  3. Clock 的输出被插入 DOM, React 调用 componentDidMount()生命周期钩子。在方法内部,Clock 组件让浏览器设置一个计时器按秒来调用组件的 tick()方法。
  4. 浏览器按秒调用 tick() 方法。其中,Clock组件通过包含当前时间的对象调用setState() 来调度 UI 更新。React通过 setState() 犯法调用知晓组件状态发生改变,随后调用 render() 方法再次知晓屏幕上应该显示什么。这时,render() 方法中 this.state.date 会发生改变,因此渲染结果将会包含更新后的时间。React 相应的更新 DOM.
  5. 如果 Clock 组件一旦移除DOM, React 调用 componentWillUnmount() 生命周期钩子,然后计时器停止。

正确的更新 State

关于setState() 的三个须知:

不要直接修改修改 State

例如,这样不会 重新渲染一个组件:

// Wrong
this.state.comment = 'Hello';

应该使用 setState():

// Correct
this.setState({comment: 'Hello'});

构造器是唯一可为 this.state 赋值的地方。

State 更新可能同步

React 为了性能可能批量多次 调用 setState() 一个单独的更新。

因为 this.propsthis.state 可能异步更新,不应该依赖它们的值来计算下一个状态。

例如,如下代码可能更新计数器失败:

// Wrong
this.setState({counter: this.state.counter + this.props.increment,
});

修复这个问题,使用 setState() 的第二种形式,接受函数而不是一个对象。这个函数接受之前的 state 作为第一个参数, 当时间更新时 props 作为第二个参数。

// Correct
this.setState((prevState, props) => ({counter: prevState.counter + props.increment
}));

上面的例子中我们使用了 [箭头函数](),但常规函数也是可以的。

// Correnct
this.setState(function(prevState, props) {return {counter: prevState.counter + props.increment};});

状态更新合并

当调用 setState(), React会合并你提供给当前状态的对象。

例如, 你的状态可能包含多个独立的变量:

constructor(props) {super(props);this.state = {posts: [],comments: []};
}

那么你可以通过分别调用 setState()独立更新他们:

  componentDidMount() {fetchPosts().then(response => {this.setState({posts: response.posts});});fetchComments().then(response => {this.setState({comments: response.comments});}); }

合并是浅的, 所以 this.setState({comments}) 保留了 this.state.posts 的完整,却完全替换了 this.state.comments.

数据流向下

无论子组件还是父组件都无法知道一个特定的主键是有状态还是无状态,而且他们也不应当关心它是用函数方式还是类方式定义。

这是为什么 state 经常被成为本地或者被封装的。它对任何组件不可达,无论是组件拥有它或者是其组成部分。

一个组件可能选择传递他的 state 向下作为 props 给它的子组件:

<h2>It is {this.state.date.toLocaleTimeString()}.</h2>

这对用户自定义组件也同样有效:

<FormattedDate date={this.state.date} />

FormattedDate 组件接受它 props 中的 date,并不知道他来自 Clock的 state,还是来自 Clock 的 props, 或者是手动输入:

function FormattedDate(props) {return <h2>It is {props.date.toLocaleTimeString()}.</h2>;
}

在线尝试

这个通常称为 "top-down(自上而下)" 或者 "unidirectional(单向)" 数据流。任何 state 总数被特定的组件所拥有,任何通过 state 传递的数据或 UI 都只能影响树形结构的下方组件。

你可以家乡组件树是一个 props 瀑布,每个组件的状态就像一个额外的水源在随机点加入它同时向下流。
为展示所有组件真正独立,我们创建一个 App 组件 渲染三个 <Clock />:

function App() {
return (

<div><Clock /><Clock /><Clock />
</div>
);

}

ReactDOM.render() {
<App />,
document.getElementById('root')

[在线尝试]()每个 **Clock** 设置他自己的计时器独立更新他们。React 应用中,无论一个组件是有状态还是无状态都被当做一个组件可随时间改变的实现细节。
你可在有状态组件中使用无状态组件,反之亦然。

相关文章:

【讨论】基于WF的流程结构

大家都知道&#xff0c;在WF中默认情况下&#xff0c;其活动是以树状结构组成的&#xff0c;简单说就是复合活动包含其子活动&#xff0c;如果子活动也是复合活动也可以包含其子活动&#xff0c;但同一个活动不能成为两个活动的子活动。这种方式被大量使用在WF自带的活动库中&a…

(C++)设计一个程序能计算一个日期加上若干天后是什么日期and计算日期差值

输入第一行表示样例个数m&#xff0c;接下来m行每行四个整数分别表示年月日和累加的天数。 输出m行&#xff0c;每行按yyyy-mm-dd的个数输出。 #include<cstdio>//判断是否是闰年 bool isLeap(int year){return (year%40&&year%100!0)||year%4000; }//用二维数…

【转载】解决Apache2+PHP上传文件大小限制的问题

原文出处&#xff1a;http://evol1216.blog.163.com/blog/static/13019958020106783623528/ 在用PHP进行文件上传的操作中&#xff0c;需要知道怎么控制上传文件大小的设置&#xff0c;而文件可传大小是受到多种因素制约的&#xff0c;现总结如下&#xff1a; 1、php.ini:uploa…

第36章 网络管理

第36章 网络管理 监听 11g的话首先写配置文件vi /u01/grid/11g/network/admin/listener.ora打开后选取下面的两个部分修改就好了 模板所在地vi /u01/11g/network/admin/samples/listener.ora SID_LIST_LISTENER (SID_LIST (SID_DESC (GLOBAL_DNAMEwyzc11g) (SID_NAMEwyzc11g)…

(C++)CSP202006-2 稀疏向量 two pointers

#include<cstdio>const int M 500000;//a,b<5*10^5 int u[M1][2];//第一维是index,第二维是value int v[M1][2];int main(){//1.读入n,a,b//2.对数组进行遍历&#xff0c;如果第一位相等&#xff0c;将第二维相乘 int n,a,b,i;long long ans0;scanf("%d%d%d&qu…

基于【CentOS-7+ Ambari 2.7.0 + HDP 3.0】搭建HAWQ数据仓库01 —— 准备环境,搭建本地仓库,安装ambari...

一、集群软硬件环境准备&#xff1a; 操作系统&#xff1a; centos 7 x86_64.1804 Ambari版本&#xff1a;2.7.0 HDP版本&#xff1a;3.0.0 HAWQ版本&#xff1a;2.3.05台PC作为工作站&#xff1a; ep-bd01ep-bd02ep-bd03ep-bd04ep-bd05其中ep-bd01作为主节点&#xff0c;用于…

PDF编辑工具——PDF Desktop Converter 4 Professional

管理和操作PDF的工具。PDF Desktop Converter 4 Professional可以生成&#xff0c;转换&#xff0c;提取&#xff0c;组合&#xff0c;分割合并PDF。新增加的OCR功能可以将扫描后的文件转变成可以检索和编辑的PDF。以上这些功能只需要一个软件就可以全部实现。软件特点1. 快速&…

史上世界上最惨烈的几次股灾!

史上世界上最惨烈的几次股灾&#xff01;●最惨烈的几次股灾 1美国股灾 1.1 1929年大股灾 1929年10月24日&#xff0c;星 期四。灾难的发生是毫无征兆的&#xff0c;开盘时&#xff0c;并没有出现什么值得注意的迹象&#xff0c;而且有一段时间股指还非常坚挺&#xff0c;但交易…

(C++) CSP 201803-1 跳一跳

#include<cstdio> const int M 30; int a[M1][2];//第一维用于读入&#xff0c;第二维用于记录上一局得分 int main(){int temp,index0,ans0;scanf("%d",&temp);while(temp!0){a[index][0]temp;if(a[index][0]1){ans1;}else{if(a[index-1][0]2){a[index][…

C#对象数组排序方法

一个排序的类&#xff0c;用了几种方式实现的。 usingSystem; namespaceDataStruct { publicclassSorter { ///<summary>///冒泡排序法1 ///</summary>/*&#xff08;1&#xff09;对于数组list中的1至n个数据&#xff0c;先将第1个和第2个数据进行比…

Asp.net MVC 3 防止 Cross-Site Request Forgery (CSRF)原理及扩展 安全 注入

原理&#xff1a;http://blog.csdn.net/cpytiger/article/details/8781457 原文地址&#xff1a;http://www.cnblogs.com/wintersun/archive/2011/12/09/2282675.html Cross-Site Request Forgery (CSRF) 是我们Web站点中常见的安全隐患。 下面我们在Asp.net MVC3 来演示一下。…

Windows下安装Redis服务

2019独角兽企业重金招聘Python工程师标准>>> Redis是有名的NoSql数据库&#xff0c;一般Linux都会默认支持。但在Windows环境中&#xff0c;可能需要手动安装设置才能有效使用。这里就简单介绍一下Windows下Redis服务的安装方法&#xff0c;希望能够帮到你。 1、要安…

(C++)1022 D进制的A+B 除基取余法将10进制数换成给定进制数

#include<cstdio> //除基取余法 const int M 30;int main(){long long a,b,c;int D,ans[M2];scanf("%lld%lld%d",&a,&b,&D);cab;int num0;do{ans[num]c%D;c c/D;}while(c!0);for(int inum-1;i>0;i--){printf("%d",ans[i]);}return…

Linux zip-tar.gz 压缩解压

tar -zcvf /home/xahot.tar.gz /xahot tar -zcvf 打包后生成的文件名全路径 要打包的目录 例子&#xff1a;把/xahot文件夹打包后生成一个/home/xahot.tar.gz的文件。zip 压缩方法&#xff1a; 压缩当前的文件夹 zip -r ./xahot.zip ./* -r表示递归zip [参数] [打包后的文件名]…

Spring(ApplicationContextBeanFactory)

BeanFactory 才是 Spring 容器中的顶层接口。ApplicationContext 是它的子接口。 BeanFactory 和 ApplicationContext 的区别&#xff1a;创建对象的时间点不一样。 BeanFactory接口 spring的原始接口,针对原始接口的实现类功能较为单一.BeanFactory接口实现类的容器,特点是每次…

spoolsv.exe占CPU100% 的解决方法

spoolsv.exe占CPU100% 的解决方法spoolsv.exe是打印缓冲&#xff0c;没有打印机就关掉&#xff0c;有的话在打印时会占用很大内存。因为要打印的文件要转化格式。禁止Print spooler服务&#xff0c;如果用打印机&#xff0c;此方法不可行。  解决办法如下&#xff1a;1、在服…

(C++)1037 在霍格沃茨找零钱的两种解法

解法一 #include<cstdio> //十七个银西可(Sickle)兑一个加隆(Galleon)&#xff0c;二十九个纳特(Knut)兑一个西可 //1 G 17 S , 1 S 29 Kint main(){int g1,s1,k1,g2,s2,k2,g3,s3,k3;scanf("%d.%d.%d",&g2,&s2,&k2);//定价 scanf("%d.%d.%…

开发人员角色分析

开发人员角色分析&#xff1a; 开发人员Developers 主要包含以下角色&#xff1a; n 软件架构师Software Architect n 设计员Designer n 用户界面设计员User-Interface Designer n 数据库设计员 Database Designer n 实施员Implementer n …

php empty()和isset()的区别

在使用 php 编写页面程序时&#xff0c;我经常使用变量处理函数判断 php 页面尾部参数的某个变量值是否为空&#xff0c;开始的时候我习惯了使用 empty() 函数&#xff0c;却发现了一些问题&#xff0c;因此改用 isset() 函数&#xff0c;问题不再。 顾名思义&#xff0c;empty…

jmap 内存情况

2019独角兽企业重金招聘Python工程师标准>>> -dump dump堆到文件,format指定输出格式&#xff0c;live指明是活着的对象,file指定文件名 [rootlocalhost ~]# jmap -dump:live,formatb,filedump.hprof 187784 Dumping heap to /home/yxgly/dump.hprof ... Heap dump …

(C++)1021 个位数统计

#include<cstdio> #include<cstring>const int M 1000;int main(){char str[M1];int count[10]{0};//全部初始化为0 scanf("%s",str);int len strlen(str);int i;for(i0;i<len;i){count[str[i]-0];}for(i0;i<10;i){if(count[i]>0){printf(&qu…

TOJ--3456--数学题

这题 做出来真的好爽啊... it is cool although it is easy 虽然 已经是大概1 2点的事了 我拖到现在才写是因为------lol 终于赢一把了 --- 先贴下题目&#xff1a; touch me 嗯 我一开始 用的是 3重for 我以为32767的数据量 是很小的.... 结果 TLE。。 OK 那么 我们只能换…

firewalled centos7

zone绑定网卡 firewall-cmd --zoneinternal --add-interfaceens192 --permanent firewall-cmd --permanent --zoneinternal --add-rich-rule"rule family"ipv4" source address"192.168.10.0/24" accept" [rootbyos000 system]# firewall-cmd -…

为Delphi程序添加事件和事件处理器

在Delphi中&#xff0c;事件实际上是专门化的属性&#xff0c;它是一个过程&#xff08;procedure&#xff09;的指针。要添加事件&#xff0c;首先应在所定义的类中说明一个用来指向事件过 程的指针&#xff0c;该指针的作用是当事件一旦发生&#xff0c;就通过这个指针执行所…

(C++)1031 查验身份证 3难点+3注意点

#include<cstdio> #include<cstring> //难点1&#xff1a;检查前17位是否全为数字 //解决之道1&#xff1a;本来就不是整型数字&#xff0c;是字符数字&#xff0c;判断是否在0和9之间即可 //难点2&#xff1a;遇到一个X后&#xff0c;如果不想处理sum了该怎么办 /…

Perl时间处理函数

官方网址&#xff1a;http://search.cpan.org/~stbey/Date-Calc-6.3/lib/Date/Calc.pod#___top use Date::Calc qw(Days_in_YearDays_in_MonthWeeks_in_Yearleap_yearcheck_datecheck_timecheck_business_dateDay_of_YearDate_to_DaysDay_of_WeekWeek_NumberWeek_of_YearMonda…

Linux环境搭建 | 手把手教你安装Linux虚拟机

2019独角兽企业重金招聘Python工程师标准>>> 前言 作为一名Linux工程师&#xff0c;不管是运维、应用、驱动方向&#xff0c;在工作中肯定会需要Linux环境。想要获得Linux环境&#xff0c;一个办法就是将电脑系统直接换成Linux系统&#xff0c;但我们平常用惯了Wind…

企业的覆灭,我监视你的Exchange邮件!

现在很多企业都搭建ExchangeServer平台&#xff0c;一个用户包括Domain admins都是不允许查阅其他用户的邮件信息的&#xff01;殊不知作为Domain Admins权限用户可以经过精心的设置&#xff0c;可以达到浏览到其他用户邮件信息&#xff01; 转载于:https://www.cnblogs.com/al…

(C++)1002 写出这个数

#include<cstdio> #include<cstring>const int M 100; //用字符数组装输入 //定义变量&#xff0c;输出字符数组的长度 //对字符数组遍历求和 //对结果逐位输出汉语拼音 void hanzi(int i){switch(i){case 0:printf("ling");break;case 1:printf("…

IO复用之epoll系列

epoll是什么&#xff1f; epoll是Linux内核为处理大批量文件描述符而作了改进的poll&#xff0c;是Linux下多路复用IO接口select/poll的增强版本&#xff0c;它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。另一点原因就是获取事件的时候&#xff0c;它…