⏰序言
对于刚学习 react
的小伙伴来说,总是从基础开始学习,周一自然也不例外捏。那在下面的文章中,将讲解 react
的基本使用和高级特性,更有周边插件 Redux
和 React-router
待你来探寻。
在本文中,融合大量案例🌰和动图🕹️进行展示。可以把它当成是 react
的入门宝库,有不懂的语法知识点时或许在这里可以寻找到你的答案并且通过例子运用起来。
叮,废话不多说,下面来开始探索 react
的奥秘吧👏
📝一、React的基本使用
1、JSX基本使用
(1)变量、表达式
在 react
中,最基础的内容便是变量和表达式,具体形式如下:
第一种类型:获取变量、插值
import React from 'react' class JSXBaseDemo extends React.Component { constructor(props) { super(props) this.state = { name: '掘金:星期一研究室', imgUrl: 'https://p3-passport.byteacctimg.com/img/user-avatar/cc88f43a329099d65898aff670ea1171~300x300.image', flag: true } } render() { // 获取变量 插值 const pElem = <p>{this.state.name}</p> return pElem } } export default JSXBaseDemo 复制代码
注意, react
中插值的形式是单个花括号 {}
的形式。最终浏览器显示的效果如下:
第二种类型:表达式
import React from 'react' class JSXBaseDemo extends React.Component { constructor(props) { super(props) this.state = { name: '掘金:星期一研究室', imgUrl: 'https://p3-passport.byteacctimg.com/img/user-avatar/cc88f43a329099d65898aff670ea1171~300x300.image', flag: true } } render() { // 表达式 const exprElem = <p>{this.state.flag ? 'yes' : 'no'}</p> return exprElem } } export default JSXBaseDemo 复制代码
react
中也支持直接在插值里面使用表达式,如上述代码中的 this.state.flag ? 'yes' : 'no'
。最终浏览器的显示效果如下:
(2)class和style
通常情况下,如果我们要给某一个标签设置类名,那么会给该标签加上一个 class
。而在 react
中,如果想要给一个标签加上一个类,那么需要给其加上 className
。具体代码如下:
import React from 'react' import './style.css' import List from '../List' class JSXBaseDemo extends React.Component { render() { // class const classElem = <p className="title">设置 css class</p> // style const styleData = { fontSize: '30px', color: 'blue' } const styleElem1 = <p style={styleData}>设置 style</p> // 内联写法,注意 {{ 和 }} const styleElem2 = <p style={{ fontSize: '30px', color: 'blue' }}>设置 style</p> // 返回结果 return [ classElem, styleElem1, styleElem2 ] } } export default JSXBaseDemo 复制代码
此时浏览器的显示效果为:
同时需要注意的是,在 react
中,如果要在标签里面写内联样式,那么需要使用双花括号{{}}
来表示。
(3)子元素和组件
第一种类型:子元素
对于子元素来说,它可以在标签里面进行使用。如下代码所示:
import React from 'react' class JSXBaseDemo extends React.Component { constructor(props) { super(props) this.state = { name: '掘金:星期一研究室', imgUrl: 'https://p3-passport.byteacctimg.com/img/user-avatar/cc88f43a329099d65898aff670ea1171~300x300.image', flag: true } } render() { // 子元素 const imgElem = <div> <p>我的头像</p> <img src="xxxx.png"/> <img src={this.state.imgUrl}/> </div> return imgElem } } export default JSXBaseDemo 复制代码
最终,浏览器的显示效果为:
第二种类型:加载组件
如果要在 React
中加载一个组件,那么我们可以这么处理。具体代码如下:
import React from 'react' import './style.css' import List from '../List' class JSXBaseDemo extends React.Component { constructor(props) { super(props) this.state = { name: '掘金:星期一研究室', imgUrl: 'https://p3-passport.byteacctimg.com/img/user-avatar/cc88f43a329099d65898aff670ea1171~300x300.image', flag: true } } render() { // 加载组件 const componentElem = <div> <p>JSX 中加载一个组件</p> <hr/> <List/> </div> return componentElem } } export default JSXBaseDemo 复制代码
List.js 组件的代码如下:
import React from 'react' class List extends React.Component { constructor(props) { super(props) this.state = { name: 'React', list: ['a', 'b', 'c'] } } render() { return <div> <p onClick={this.changeName.bind(this)}>{this.state.name}</p> <ul>{ this.state.list.map((item, index) => { return <li key={index}>{item}</li> }) }</ul> <button onClick={this.addItem.bind(this)}>添加一项</button> </div> } changeName() { this.setState({ name: '星期一研究室' }) } addItem() { this.setState({ list: this.state.list.concat(`${Date.now()}`) // 使用不可变值 }) } } export default List 复制代码
此时浏览器的显示效果如下:
由此,我们就将一个组件注入到组件当中。
(4)原生 html
继续,我们来看原生 html
在 react
中是如何使用的。先看以下代码:
import React from 'react' class JSXBaseDemo extends React.Component { render() { // 原生 html const rawHtml = '<span>富文本内容<i>斜体</i><b>加粗</b></span>' const rawHtmlData = { // 把 rawHtml 赋值给 __html __html: rawHtml // 注意,必须是这种格式 } const rawHtmlElem = <div> <p dangerouslySetInnerHTML={rawHtmlData}></p> <p>{rawHtml}</p> </div> return rawHtmlElem } } export default JSXBaseDemo 复制代码
此时浏览器的显示效果如下:
大家可以看到,如果要在 react
中使用原生 html
,那么必须使用 const rawHtmlData = { __html: rawHtml }
这种形式,才能将原生 html
代码给解析出来。否则的话, react
是无法正常将原生 html
解析出来的。
2、条件判断
(1)if else
先看下面这段代码:
import React from 'react' import './style.css' class ConditionDemo extends React.Component { constructor(props) { super(props) this.state = { theme: 'black' } } render() { const blackBtn = <button className="btn-black">black btn</button> const whiteBtn = <button className="btn-white">white btn</button> // if else if (this.state.theme === 'black') { return blackBtn } else { return whiteBtn } } } export default ConditionDemo 复制代码
style.css 的代码如下:
.title { font-size: 30px; color: red; } .btn-white { color: #333; } .btn-black { background-color: #666; color: #fff;; } 复制代码
此时浏览器的显示效果为:
大家可以看到,当我们 theme
设置为 black
时,最终显示的效果就是黑色。如果我们把 theme
设置为其他状态,那么最终显示的效果就是白色。
(2)三元表达式
先来看一段代码:
import React from 'react' import './style.css' class ConditionDemo extends React.Component { constructor(props) { super(props) this.state = { theme: 'black' } } render() { const blackBtn = <button className="btn-black">black btn</button> const whiteBtn = <button className="btn-white">white btn</button> // 三元运算符 return <div> { this.state.theme === 'black' ? blackBtn : whiteBtn } </div> } } export default ConditionDemo 复制代码
此时浏览器的显示效果为:
大家可以看到,我们也可以通过三元表达式 this.state.theme === 'black' ? blackBtn : whiteBtn
的方式来对一些条件进行判断。
(3)逻辑运算符 && ||
先来看一段代码:
import React from 'react' import './style.css' class ConditionDemo extends React.Component { constructor(props) { super(props) this.state = { theme: 'black' } } render() { const blackBtn = <button className="btn-black">black btn</button> const whiteBtn = <button className="btn-white">white btn</button> // && return <div> { this.state.theme === 'black' && blackBtn } </div> } } export default ConditionDemo 复制代码
此时浏览器的显示结果也是和上述一样的。具体如下:
this.state.theme === 'black' && blackBtn
这句话的意思为,如果 this.state.theme
的值为 black
时,那么返回 backBtn
的结果。
3、渲染列表
(1)map 和 key
先来看一段代码:
import React from 'react' class ListDemo extends React.Component { constructor(props) { super(props) this.state = { list: [ { id: 'id-1', title: '标题1' }, { id: 'id-2', title: '标题2' }, { id: 'id-3', title: '标题3' } ] } } render() { return <ul> { /* 类似于vue中的v-for */ this.state.list.map( (item, index) => { // 这里的 key 和 Vue 的 key 类似,必填,不能是 index 或 random return <li key={item.id}> index {index}; id {item.id}; title {item.title} </li> } ) } </ul> } } export default ListDemo 复制代码
此时浏览器的显示效果如下:
在 react
中,使用的是 list.map
来渲染列表。其中, 需要注意的是, list.map()
是一个函数,那现在我们假设这个函数里面要遵循一套规则 list.map( item => item.id )
。
这个时候,我们视 .map
为一个数组的重组,那么重组的规则就是 item => item.id
。同时, list.map
返回的是一个数组。
4、React的事件
(1)bind this
先来看一段代码:
import React from 'react' class EventDemo extends React.Component { constructor(props) { super(props) this.state = { name: 'zhangsan' } // 修改方法的 this 指向 // 使用这个写法,组件初始化时,只执行一次bind this.clickHandler1 = this.clickHandler1.bind(this) } render() { // this - 使用 bind return <p onClick={this.clickHandler1}> {this.state.name} </p> } clickHandler1() { // console.log('this....', this) // this 默认是 undefined this.setState({ name: 'lisi' }) } } export default EventDemo 复制代码
最终浏览器显示的效果为:
在这段代码中,我们通过 this.clickHandler1 = this.clickHandler1.bind(this)
来对 clickHandler1
进行绑定。
还有另外一种关于 this
的绑定方法。先来看一段代码:
import React from 'react' class EventDemo extends React.Component { constructor(props) { super(props) this.state = { name: 'zhangsan' } } render() { // this - 使用静态方法 return <p onClick={this.clickHandler2}> clickHandler2 {this.state.name} </p> } // 静态方法,this 指向当前实例 clickHandler2 = () => { this.setState({ name: 'lisi' }) } } export default EventDemo 复制代码
此时浏览器的显示效果为:
对于上面的这种方式来说, clickHandler2
是一个静态方法,此时它的 this
会指向当前的实例。
(2)关于 event 参数
先来看一段代码:
import React from 'react' class EventDemo extends React.Component { constructor(props) { super(props) this.state = { name: 'zhangsan' } } render() { // event return <a href="https://imooc.com/" onClick={this.clickHandler3}> click me </a> } // 获取 event (重点) clickHandler3 = (event) => { event.preventDefault() // 阻止默认行为 event.stopPropagation() // 阻止冒泡 console.log('target', event.target) // 指向当前元素,即当前元素触发 console.log('current target', event.currentTarget) // 指向当前元素,假象!!! // 注意,event 其实是 React 封装的。可以把 __proto__.constructor 看成是 SyntheticEvent 组合事件 console.log('event', event) // 不是原生的 Event ,原生的是 MouseEvent console.log('event.__proto__.constructor', event.__proto__.constructor) // 原生 event 如下。其 __proto__.constructor 是 MouseEvent console.log('nativeEvent', event.nativeEvent) console.log('nativeEvent target', event.nativeEvent.target) // 指向当前元素,即当前元素触发 console.log('nativeEvent current target', event.nativeEvent.currentTarget) // 指向 document !!! } } export default EventDemo 复制代码
此时浏览器的显示效果如下:
依据以上内容,需要注意的点是:
event
是合成事件SyntheticEvent
,它能够模拟出来DOM
事件所有的能力;event
是React
封装出来的,而event.nativeEvent
是原生事件对象;- 所有的事件,都会被挂载到
document
上; React
中的事件,和DOM
事件不一样,和Vue
事件也不一样。
(3)传递自定义参数
先来看一段代码:
import React from 'react' class EventDemo extends React.Component { constructor(props) { super(props) this.state = { name: 'zhangsan', list: [ { id: 'id-1', title: '标题1' }, { id: 'id-2', title: '标题2' }, { id: 'id-3', title: '标题3' } ] } } render() { // 传递参数 - 用 bind(this, a, b) return <ul>{this.state.list.map((item, index) => { return <li key={item.id} onClick={this.clickHandler4.bind(this, item.id, item.title)}> index {index}; title {item.title} </li> })}</ul> } // 传递参数 clickHandler4(id, title, event) { console.log(id, title) console.log('event', event) // 最后追加一个参数,即可接收 event } } export default EventDemo 复制代码
此时,浏览器的显示效果为:
大家可以看到,我们通过使用 this.clickHandler4.bind(this, item.id, item.title)
这种形式来对 react
中的事件进行参数传递。
(4)注意点
React 16
将事件绑定到document
上;React 17
将事件绑定到root
组件上;- 这样做的好处在于:有利于多个
React
版本并存,例如微前端。
如下图所示:
5、表单
(1)受控组件
先来看一段代码:
import React from 'react' class FormDemo extends React.Component { constructor(props) { super(props) this.state = { name: '星期一研究室', info: '个人信息', city: 'GuangDong', flag: true, gender: 'female' } } render() { // 受控组件 return <div> <p>{this.state.name}</p> <label htmlFor="inputName">姓名:</label> {/* 用 htmlFor 代替 for */} <input id="inputName" value={this.state.name} onChange={this.onInputChange}/> </div> } onInputChange = (e) => { this.setState({ name: e.target.value }) } } export default FormDemo 复制代码
此时浏览器的显示效果如下:
在 react
中,通过使用 onChange
事件来手动修改 state
里面的值。
(2)input textarea select 用value
上面我们已经讲解了 input
,接下来我们来看 textarea
和 select
。
先来看 textarea
相关的代码:
import React from 'react' class FormDemo extends React.Component { constructor(props) { super(props) this.state = { name: '星期一研究室', info: '个人信息', city: 'GuangDong', flag: true, gender: 'female' } } render() { // textarea - 使用 value return <div> <textarea value={this.state.info} onChange={this.onTextareaChange}/> <p>{this.state.info}</p> </div> } onTextareaChange = (e) => { this.setState({ info: e.target.value }) } } export default FormDemo 复制代码
此时浏览器的打印效果是:
同样地, textarea
也是用 value
和 onChange
来对值进行绑定。
继续来看 select
。具体代码如下:
import React from 'react' class FormDemo extends React.Component { constructor(props) { super(props) this.state = { name: '星期一研究室', info: '个人信息', city: 'GuangDong', flag: true, gender: 'female' } } render() { // select - 使用 value return <div> <select value={this.state.city} onChange={this.onSelectChange}> <option value="beijing">北京</option> <option value="shanghai">上海</option> <option value="shenzhen">深圳</option> </select> <p>{this.state.city}</p> </div> } onSelectChange = (e) => { this.setState({ city: e.target.value }) } } export default FormDemo 复制代码
此时,浏览器的显示效果为:
与 input
和 textarea
一样,也是通过操作 value
和 onChange
,来改变最终的值。
(3)checkbox radio 用 checked
先来看 ckeckbox
。代码如下:
import React from 'react' class FormDemo extends React.Component { constructor(props) { super(props) this.state = { name: '星期一研究室', info: '个人信息', city: 'GuangDong', flag: true, gender: 'female' } } render() { // checkbox return <div> <input type="checkbox" checked={this.state.flag} onChange={this.onCheckboxChange}/> <p>{this.state.flag.toString()}</p> </div> } onCheckboxChange = () => { this.setState({ flag: !this.state.flag }) } } export default FormDemo 复制代码
此时浏览器的显示效果为:
在上面的代码中, checkbox
通过操作 checked
和 onChange
,来改变 state
的值。
radio
也是类似,如下代码所示:
import React from 'react' class FormDemo extends React.Component { constructor(props) { super(props) this.state = { name: '星期一研究室', info: '个人信息', city: 'GuangDong', flag: true, gender: 'female' } } render() { // radio return <div> male <input type="radio" name="gender" value="male" checked={this.state.gender === 'male'} onChange={this.onRadioChange}/> female <input type="radio" name="gender" value="female" checked={this.state.gender === 'female'} onChange={this.onRadioChange}/> <p>{this.state.gender}</p> </div> } onRadioChange = (e) => { this.setState({ gender: e.target.value }) } } export default FormDemo 复制代码
此时浏览器的显示效果是:
6、组件使用
对于父子组件的使用来说,我们需要明白三个知识点:props
传递数据、props
传递函数和 props
类型检查。
先来看一段代码:
import React from 'react' import PropTypes from 'prop-types' class Input extends React.Component { constructor(props) { super(props) this.state = { title: '' } } render() { return <div> <input value={this.state.title} onChange={this.onTitleChange}/> <button onClick={this.onSubmit}>提交</button> </div> } onTitleChange = (e) => { this.setState({ title: e.target.value }) } onSubmit = () => { const { submitTitle } = this.props submitTitle(this.state.title) this.setState({ title: '' }) } } // props 类型检查 Input.propTypes = { submitTitle: PropTypes.func.isRequired } class List extends React.Component { constructor(props) { super(props) } render() { const { list } = this.props return <ul>{list.map((item, index) => { return <li key={item.id}> <span>{item.title}</span> </li> })}</ul> } } // props 类型检查 // 通过propTypes可以清楚地知道list需要一个什么类型的数据 List.propTypes = { list: PropTypes.arrayOf(PropTypes.object).isRequired } class Footer extends React.Component { constructor(props) { super(props) } render() { return <p> {this.props.text} {this.props.length} </p> } componentDidUpdate() { console.log('footer did update') } shouldComponentUpdate(nextProps, nextState) { if (nextProps.text !== this.props.text || nextProps.length !== this.props.length) { return true // 可以渲染 } return false // 不重复渲染 } // React 默认:父组件有更新,子组件则无条件也更新!!! // 性能优化对于 React 更加重要! // SCU 一定要每次都用吗?—— 需要的时候才优化(SCU即shouldComponentUpdate) } // 父组件 class TodoListDemo extends React.Component { constructor(props) { super(props) // 状态(数据)提升 // list的数据需要放在父组件 this.state = { list: [ { id: 'id-1', title: '标题1' }, { id: 'id-2', title: '标题2' }, { id: 'id-3', title: '标题3' } ], footerInfo: '底部文字' } } render() { return <div> <Input submitTitle={this.onSubmitTitle}/> <List list={this.state.list}/> <Footer text={this.state.footerInfo} length={this.state.list.length}/> </div> } onSubmitTitle = (title) => { this.setState({ list: this.state.list.concat({ id: `id-${Date.now()}`, title }) }) } } export default TodoListDemo 复制代码
此时浏览器的显示效果如下:
依据以上代码,我们来对 props
的各个类型进行介绍。
(1)props 传递数据
最后一个 TodoListDemo
是父组件,其他都是子组件。在 Input
组件和 List
组件中,我们将 props
属性的内容,以 this.props.xxx
的方式,传递给父组件。
(2)props 传递函数
React
在传递函数这一部分和 vue
是不一样的。对于 vue
来说,如果有一个父组件要传递函数给子组件,子组件如果想要触发这个函数,那么需要使用事件传递和 $emit
的方式来解决。
大家定位到 Input
组件中,在这里,我们将 submitTitle
以函数的形式,传递给父组件中的 onSubmitTitle
。
(3)props 类型检查
大家定位到两处 props
类型检查的地方。使用 react
中的 PropTypes
,我们可以对当前所使用的属性进行一个类型检查。比如说: submitTitle: PropTypes.func.isRequired
表明的是, submitTitle
是一个函数,并且是一个必填项。
就这样,通过上面的例子,我们学习了属性传递、属性验证以及父组件和子组件之间怎么通过传事件的形式来进行通信。
7、setState
(1)不可变值
所谓不可变值,即所设置的值永不改变。那这个时候,我们就需要去创建一个副本,来设置 state
的值。
来看几个要点:
第一点:state 要在构造函数中定义。如下代码所示:
import React from 'react' // 函数组件,默认没有 state class StateDemo extends React.Component { constructor(props) { super(props) // 第一,state 要在构造函数中定义 this.state = { count: 0 } } render() { return <div> <p>{this.state.count}</p> </div> } } export default StateDemo 复制代码
第二点,不要直接修改 state ,要使用不可变值。如下代码所示:
import React from 'react' // 函数组件,默认没有 state class StateDemo extends React.Component { constructor(props) { super(props) // 第一,state 要在构造函数中定义 this.state = { count: 0 } } render() { return <div> <p>{this.state.count}</p> <button onClick={this.increase}>累加</button> </div> } increase= () => { // 第二,不要直接修改 state,使用不可变值 // this.state.count++ // 错误写法,会直接修改原来的值 this.setState({ count: this.state.count + 1 // ShouldComponentUpdate → SCU }) } } export default StateDemo 复制代码
大家可以看到,在上面的代码中,我们通过 this.state({})
这种形式,来修改 state
的值。值得注意的是,很多小伙伴会直接使用 this.state.count++
来修改 state
的值,这在 react
中是非常不允许的。因此,要注意这个要点。
第三点,在 react
中操作数组的值。如下代码所示:
// 不可变值(函数式编程,纯函数) - 数组 const list5Copy = this.state.list5.slice() list5Copy.splice(2, 0, 'a') // 中间插入/删除 this.setState({ list1: this.state.list1.concat(100), // 追加 list2: [...this.state.list2, 100], // 追加 list3: this.state.list3.slice(0, 3), // 截取 list4: this.state.list4.filter(item => item > 100), // 筛选 list5: list5Copy // 其他操作 }) // 注意,不能直接对 this.state.list 进行 push pop splice 等,这样违反不可变值 复制代码
第四点,在 react
中操作对象的值。如下代码所示:
// 不可变值 - 对象 this.setState({ obj1: Object.assign({}, this.state.obj1, {a: 100}), obj2: {...this.state.obj2, a: 100} }) // 注意,不能直接对 this.state.obj 进行属性设置,即 this.state.obj.xxx 这样的形式,这种形式会违反不可变值 复制代码
(2)可能是异步更新
react
中的 state
,有可能是异步更新。来看一段代码:
import React from 'react' class StateDemo extends React.Component { constructor(props) { super(props) this.state = { count: 0 } } render() { return <div> <p>{this.state.count}</p> <button onClick={this.increase}>累加</button> </div> } increase= () => { // setState 可能是异步更新(也有可能是同步更新) this.setState({ count: this.state.count + 1 }, () => { // 联想 Vue $nextTick - DOM console.log('count by callback', this.state.count) // 回调函数中可以拿到最新的 state }) console.log('count', this.state.count) // 异步的,拿不到最新值 } } export default StateDemo 复制代码
此时浏览器的显示效果为:
大家可以看到,this.state
前半部分并不能同一时间得到更新,所以它是异步操作。而后面的箭头函数中的内容可以得到同步更新,所以后面函数的部分是同步操作。
值得注意的是, setTimeout
在 setState
中是同步的。来看一段代码:
import React from 'react' class StateDemo extends React.Component { constructor(props) { super(props) this.state = { count: 0 } } render() { return <div> <p>{this.state.count}</p> <button onClick={this.increase}>累加</button> </div> } increase= () => { // setTimeout 中 setState 是同步的 setTimeout(() => { this.setState({ count: this.state.count + 1 }) console.log('count in setTimeout', this.state.count) }, 0) } } export default StateDemo 复制代码
此时,浏览器的显示效果为:
还有一个要注意的点是,如果是自己定义的 DOM
事件,那么在 setState
中是同步的,用在 componentDidMount
中。
如果是销毁事件,那么用在 componentWillMount
生命周期中。代码如下:
import React from 'react' class StateDemo extends React.Component { constructor(props) { super(props) this.state = { count: 0 } } render() { return <div> <p>{this.state.count}</p> <button onClick={this.increase}>累加</button> </div> } bodyClickHandler = () => { this.setState({ count: this.state.count + 1 }) console.log('count in body event', this.state.count) } componentDidMount() { // 自己定义的 DOM 事件,setState 是同步的 document.body.addEventListener('click', this.bodyClickHandler) } componentWillUnmount() { // 及时销毁自定义 DOM 事件 document.body.removeEventListener('click', this.bodyClickHandler) // clearTimeout } } export default StateDemo 复制代码
此时浏览器的显示效果为:
(3)可能会被合并
setState
在传入对象时,更新前会被合并。来看一段代码:
import React from 'react' class StateDemo extends React.Component { constructor(props) { super(props) this.state = { count: 0 } } render() { return <div> <p>{this.state.count}</p> <button onClick={this.increase}>累加</button> </div> } increase= () => { // 传入对象,会被合并(类似 Object.assign )。执行结果只一次 +1 this.setState({ count: this.state.count + 1 }) this.setState({ count: this.state.count + 1 }) this.setState({ count: this.state.count + 1 }) } } export default StateDemo 复制代码
此时浏览器的显示效果为:
有小伙伴可能会觉得,一下子多个三个 setState
,那结果应该是 +3
才是。但其实,如果传入的是对象,那么结果会把三个合并为一个,最终只执行一次。
还有另外一种情况,如果传入的是函数,那么结果不会被合并。来看一段代码:
import React from 'react' class StateDemo extends React.Component { constructor(props) { super(props) this.state = { count: 0 } } render() { return <div> <p>{this.state.count}</p> <button onClick={this.increase}>累加</button> </div> } increase= () => { // 传入函数,不会被合并。执行结果是 +3 this.setState((prevState, props) => { return { count: prevState.count + 1 } }) this.setState((prevState, props) => { return { count: prevState.count + 1 } }) this.setState((prevState, props) => { return { count: prevState.count + 1 } }) } } export default StateDemo 复制代码
此时浏览器的显示效果为:
大家可以看到,如果传入的是函数,那么结果一下子就执行三次了。
8、组件生命周期
react
的组件生命周期,有单组件声明周期和父子组件声明周期。其中,父子组件生命周期与 Vue
类似。
这里附上一个生命周期相关的网站:projects.wojtekmaj.pl/react-lifec…
下面附上生命周期的图: