A Bite Of React(2) Component, Props and State
component
- component:用户自己定义的元素
const element = <Welcome name="Sara" />;
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
遇到自己定义的component Welcom,React会将它的属性(name)作为对象传递给组建Welcom,即{name='Sara'}
eg:components名称必须以大写字母开头,<div />
表示一个DOM标签,但 <Welcome />
表示一个组件,并且在使用该组件时你必须定义或引入它。
- 组合component:component可以在输出中引用其他的组建。一个新的React应用程序的顶部是一个
App
组件。但是,如果要将React集成到现有应用程序中,则可以从下而上使用像Button
这样的小组件作为开始,并逐渐运用到视图层的顶部。
- 组合component:component可以在输出中引用其他的组建。一个新的React应用程序的顶部是一个
eg:
警告:
组件的返回值只能有一个根元素。这也是我们要用一个
<div>
来包裹所有<Welcome />
元素的原因。
- 提取component
Props
- props:props其实就是自定义组件的属性,会打包作为一个object传递给component
props的只读性:无论是functional based component 还是 class based component都不能修改自己的props
State
如何定义state:
React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。React 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。
- State必须能代表一个组件UI呈现的完整状态集,即组件的任何UI改变,都可以从State的变化中反映出来;同时,State还必须是代表一个组件UI呈现的最小状态集,即State中的所有状态都是用于反映组件UI的变化,没有任何多余的状态,也不需要通过其他状态计算而来的中间状态。
- 组件中用到的一个变量是不是应该作为组件State,可以通过下面的4条依据进行判断:
- 这个变量是否是通过Props从父组件中获取?如果是,那么它不是一个状态。
- 这个变量是否在组件的整个生命周期中都保持不变?如果是,那么它不是一个状态。
- 这个变量是否可以通过其他状态(State)或者属性(Props)计算得到?如果是,那么它不是一个状态。
- 这个变量是否在组件的render方法中使用?如果不是,那么它不是一个状态。这种情况下,这个变量更适合定义为组件的一个普通属性,例如组件中用到的定时器,就应该直接定义为this.timer,而不是this.state.timer。
State和prop的区别:
除了State, 组件的Props也是和组件的UI有关的。他们之间的主要区别是:State是可变的,是组件内部维护的一组用于反映组件UI变化的状态集合;而Props对于使用它的组件来说,是只读的,要想修改Props,只能通过该组件的父组件修改。在组件状态上移的场景中,父组件正是通过子组件的Props, 传递给子组件其所需要的状态。
如何证正确的修改State
- 不能直接修改state:在constructor之中用this.state来初始化state(是一个object)。在其余的地方用this.setState()来更新。
- State的更新是异步的:调用
setState
,组件的state并不会立即改变,setState
只是把要修改的状态放入一个队列中,React会优化真正的执行时机,并且React会出于性能原因,可能会将多次setState
的状态修改合并成一次状态修改。所以不要依赖当前的State,计算下个State。当真正执行状态修改时,依赖的this.state并不能保证是最新的State,因为React会把多次State的修改合并成一次,这时,this.state将还是这几次State修改前的State。另外需要注意的事,同样不能依赖当前的Props计算下个状态,因为Props一般也是从父组件的State中获取,依然无法确定在组件状态更新时的值。
举个例子,对于一个电商类应用,在我们的购物车中,当我们点击一次购买数量按钮,购买的数量就会加1,如果我们连续点击了两次按钮,就会连续调用两次this.setState({quantity: this.state.quantity + 1})
,在React合并多次修改为一次的情况下,相当于等价执行了如下代码:
Object.assign(
previousState,
{quantity: this.state.quantity + 1},
{quantity: this.state.quantity + 1}
)
于是乎,后面的操作覆盖掉了前面的操作,最终购买的数量只增加了1个。
如果你真的有这样的需求,可以使用另一个接收一个函数作为参数的setState
,这个函数有两个参数,第一个是当前最新状态(本次组件状态修改后的状态)的前一个状态preState(本次组件状态修改前的状态),第二个参数是当前最新的属性props。如下所示:
// 正确
this.setState((preState, props) => {
counter: preState.quantity + 1;
})
- State 的更新是一个浅合并(Shallow Merge)的过程。
当调用setState修改组件状态时,只需要传入发生改变的State,而不是组件完整的State,因为组件State的更新是一个浅合并(Shallow Merge)的过程。例如,一个组件的状态为:
this.state = {
title : 'React',
content : 'React is an wonderful JS library!'
}
当只需要修改状态title
时,只需要将修改后的title
传给setState
:
this.setState({title: 'Reactjs'});
React会合并新的title
到原来的组件状态中,同时保留原有的状态content
,合并后的State为:
{
title : 'Reactjs',
content : 'React is an wonderful JS library!'
}
如何证正确的修改State
React官方建议把State当作是不可变对象,一方面是如果直接修改this.state,组件并不会重新render;另一方面State中包含的所有状态都应该是不可变对象。当State中的某个状态发生变化,我们应该重新创建这个状态对象,而不是直接修改原来的状态。那么,当状态发生变化时,如何创建新的状态呢?根据状态的类型,可以分成三种情况:
- 状态的类型是不可变类型(数字,字符串,布尔值,null, undefined)
这种情况最简单,因为状态是不可变类型,直接给要修改的状态赋一个新值即可。如要修改count(数字类型)、title(字符串类型)、success(布尔类型)三个状态:
this.setState({
count: 1,
title: 'Redux',
success: true
})
- 状态的类型是数组
如有一个数组类型的状态books,当向books中增加一本书时,使用数组的concat方法或ES6的数组扩展语法(spread syntax):
// 方法一:将state先赋值给另外的变量,然后使用concat创建新数组
var books = this.state.books;
this.setState({
books: books.concat(['React Guide']);
}) // 方法二:使用preState、concat创建新数组
this.setState(preState => ({
books: preState.books.concat(['React Guide']);
})) // 方法三:ES6 spread syntax
this.setState(preState => ({
books: [...preState.books, 'React Guide'];
}))
当从books中截取部分元素作为新状态时,使用数组的slice方法:
// 方法一:将state先赋值给另外的变量,然后使用slice创建新数组
var books = this.state.books;
this.setState({
books: books.slice(1,3);
}) // 方法二:使用preState、slice创建新数组
this.setState(preState => ({
books: preState.books.slice(1,3);
}))
当从books中过滤部分元素后,作为新状态时,使用数组的filter方法:
// 方法一:将state先赋值给另外的变量,然后使用filter创建新数组
var books = this.state.books;
this.setState({
books: books.filter(item => {
return item != 'React';
});
}) // 方法二:使用preState、filter创建新数组
this.setState(preState => ({
books: preState.books.filter(item => {
return item != 'React';
});
}))
注意不要使用push、pop、shift、unshift、splice等方法修改数组类型的状态,因为这些方法都是在原数组的基础上修改,而concat、slice、filter会返回一个新的数组。
- 状态的类型是普通对象(不包括字符串,数组)
ES6的Object.assign方法
// 方法一:将state先赋值给另外的变量,然后使用Object.assign创建新对象
var owner = this.setState.owner;
this.setState({
owner: Object.assign({}, owner, {name: 'Jason'});
}) // 方法二:使用preState、Object.assign创建新对象
this.setState(preState => ({
owner: Object.assign({}, preState.owner, {name: 'Jason'});
}))
使用对象扩展语法
// 方法一:将state先赋值给另外的变量,然后使用对象扩展语法创建新对象
var owner = this.setState.owner;
this.setState({
owner: {...owner, {name: 'Jason'}};
}) // 方法二:使用preState、对象扩展语法创建新对象
this.setState(preState => ({
owner: {...preState.owner, {name: 'Jason'}};
}))
来源:https://juejin.im/entry/59522bdb6fb9a06b9a516113
https://doc.react-china.org/docs/state-and-lifecycle.html
A Bite Of React(2) Component, Props and State的更多相关文章
- [React] Spread Component Props in JSX with React
You often find duplication between the name of a prop and a variable you will assign to the prop. JS ...
- 前端(十一):props、state及redux关系梳理
所谓状态机,是一种抽象的数据模型,是“事物发展的趋势”,其原理是事件驱动.广泛地讲,世界万物都是状态机. 一.状态机是一种抽象的数据模型 在react中,props和state都可以用来传递数据.这里 ...
- react native中对props和state的理解
最近使用react native这个新的技术做完一个项目,所以赶紧写个博客巩固一下. 今天我想说的是props和state,当然这是我个人的理解,如果有什么不对的地方,望指正. 首先我先说说props ...
- [React] React Fundamentals: Component Lifecycle - Updating
The React component lifecycle will allow you to update your components at runtime. This lesson will ...
- React入门---属性(props)-8
Props 和 State对于组件Component是非常重要的两个属性. 区别:State对于模块来说是 自身属性: Props对于模块来说是 外来属性: 同样的,props也是只作用于当前的组 ...
- React 深入系列3:Props 和 State
文:徐超,<React进阶之路>作者 授权发布,转载请注明作者及出处 React 深入系列3:Props 和 State React 深入系列,深入讲解了React中的重点概念.特性和模式 ...
- React Native基础&入门教程:以一个To Do List小例子,看props和state
本文由葡萄城技术团队于博客园原创并首发 转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 在上篇中,我们介绍了什么是Flexbox布局,以及如何使用Flexb ...
- 从 0 到 1 实现 React 系列 —— 2.组件和 state|props
看源码一个痛处是会陷进理不顺主干的困局中,本系列文章在实现一个 (x)react 的同时理顺 React 框架的主干内容(JSX/虚拟DOM/组件/生命周期/diff算法/setState/ref/. ...
- React中Props 和 State用法
React中Props 和 State用法 1.本质 一句话概括,props 是组件对外的接口,state 是组件对内的接口.组件内可以引用其他组件,组件之间的引用形成了一个树状结构(组件树),如果下 ...
随机推荐
- Crash的数字表格(莫比乌斯反演)
Crash的数字表格 Description 今天的数学课上,Crash小朋友学习了最小公倍数(Least Common Multiple).对于两个正整数a和b,LCM(a, b)表示能同时被a和b ...
- AJAX —— JSON 字符串 与 JSON 对象
一.JSON 字符串转 JSON 对象 ----> JSON.parse(JString); 1 // JSON 字符串转 JSON 对象 ----> JSON.parse(JString ...
- reids 持久化
RDB: RDB是整个内存压缩过的Snapshot,RDB 的数据结构,可以配置符合的快照触发条件,默认如下 900s 1次修改 300s 10次修改 60s 10000 次修改 自动备份为dump ...
- .net core webapi添加swagger
依赖项——右键——管理NuGet程序包——浏览——输入以下内容 Install-Package Swashbuckle.AspNetCore -Pre 双击Properties——点击生成——勾选XM ...
- html/css 实现下拉菜单效果
demo.html <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...
- ConcurrentLinkedQueue和LinkedBlockingQueue区别
原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/11394436.html 线程安全队列类图 两者的区别在于 ConcurrentLinkedQueue基 ...
- This MySqlConnection is already in use
项目中类似于以下的代码,实际的代码要更复杂,DbContext是依赖注入的: 报错如下: This MySqlConnection is already in use. See https://fl. ...
- 最强DE战斗力
最强DE战斗力 时间限制: 1 Sec 内存限制: 128 MB提交: 40 解决: 14[提交][状态] 题目描述 春秋战国时期,赵国地大物博,资源非常丰富,人民安居乐业.但许多国家对它虎视眈眈 ...
- 创建Spring Boot 工程
先在eclipse中安装spring -tool -suite插件,然后根据以下步骤可以创建 1.新建Spring Starter Project 2.Packaging 选择 jar 3.勾选W ...
- 安装和使用Redis【转】
Redis是一个高性能的内存数据库,它体积轻巧性能又高,在企业中被广泛使用. 安装Redis Windows安装 Redis是为Linux系统设计的,但是也有团队为Windows做了移植.我们可以到这 ...