不止前端React【不止前端】 React基础入门1
余生⏰序言
对于刚学习 react
的小伙伴来说,总是从基础开始学习,周一自然也不例外捏。那在下面的文章中,将讲解 react
的基本使用和高级特性,更有周边插件 Redux
和 React-router
待你来探寻。
在本文中,融合大量案例🌰和动图🕹️进行展示。可以把它当成是 react
的入门宝库,有不懂的语法知识点时或许在这里可以寻找到你的答案并且通过例子运用起来。
叮,废话不多说,下面来开始探索 react
的奥秘吧👏
📝一、React的基本使用
1、JSX基本使用
(1)变量、表达式
在 react
中,最基础的内容便是变量和表达式,具体形式如下:
第一种类型:获取变量、插值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 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
中插值的形式是单个花括号 {}
的形式。最终浏览器显示的效果如下:
第二种类型:表达式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 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
。具体代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import React from 'react' import './style.css' import List from '../List'
class JSXBaseDemo extends React.Component { render() { const classElem = <p className="title">设置 css class</p>
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)子元素和组件
第一种类型:子元素
对于子元素来说,它可以在标签里面进行使用。如下代码所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| js复制代码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
中加载一个组件,那么我们可以这么处理。具体代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| 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 组件的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| 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
中是如何使用的。先看以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import React from 'react'
class JSXBaseDemo extends React.Component { render() { const rawHtml = '<span>富文本内容<i>斜体</i><b>加粗</b></span>' const rawHtmlData = { __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
先看下面这段代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| 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 (this.state.theme === 'black') { return blackBtn } else { return whiteBtn } } }
export default ConditionDemo
|
style.css 的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12
| .title { font-size: 30px; color: red; }
.btn-white { color: #333; } .btn-black { background-color: #666; color: #fff;; }
|
此时浏览器的显示效果为:
大家可以看到,当我们 theme
设置为 black
时,最终显示的效果就是黑色。如果我们把 theme
设置为其他状态,那么最终显示的效果就是白色。
(2)三元表达式
先来看一段代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| 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)逻辑运算符 && ||
先来看一段代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| 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
先来看一段代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| 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
先来看一段代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| import React from 'react'
class EventDemo extends React.Component { constructor(props) { super(props) this.state = { name: 'zhangsan' }
this.clickHandler1 = this.clickHandler1.bind(this) } render() { return <p onClick={this.clickHandler1}> {this.state.name} </p> } clickHandler1() { this.setState({ name: 'lisi' }) } }
export default EventDemo
|
最终浏览器显示的效果为:
在这段代码中,我们通过 this.clickHandler1 = this.clickHandler1.bind(this)
来对 clickHandler1
进行绑定。
还有另外一种关于 this
的绑定方法。先来看一段代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import React from 'react'
class EventDemo extends React.Component { constructor(props) { super(props) this.state = { name: 'zhangsan' } } render() { return <p onClick={this.clickHandler2}> clickHandler2 {this.state.name} </p> } clickHandler2 = () => { this.setState({ name: 'lisi' }) } }
export default EventDemo
|
此时浏览器的显示效果为:
对于上面的这种方式来说, clickHandler2
是一个静态方法,此时它的 this
会指向当前的实例。
(2)关于 event 参数
先来看一段代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| import React from 'react'
class EventDemo extends React.Component { constructor(props) { super(props) this.state = { name: 'zhangsan' } } render() { return <a href="https://imooc.com/" onClick={this.clickHandler3}> click me </a> } clickHandler3 = (event) => { event.preventDefault() event.stopPropagation() console.log('target', event.target) console.log('current target', event.currentTarget)
console.log('event', event) console.log('event.__proto__.constructor', event.__proto__.constructor)
console.log('nativeEvent', event.nativeEvent) console.log('nativeEvent target', event.nativeEvent.target) console.log('nativeEvent current target', event.nativeEvent.currentTarget)
} }
export default EventDemo
|
此时浏览器的显示效果如下:
依据以上内容,需要注意的点是:
event
是合成事件 SyntheticEvent
,它能够模拟出来 DOM
事件所有的能力;
event
是React
封装出来的,而 event.nativeEvent
是原生事件对象;
- 所有的事件,都会被挂载到
document
上;
React
中的事件,和 DOM
事件不一样,和 Vue
事件也不一样。
(3)传递自定义参数
先来看一段代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| 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() { 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) } }
export default EventDemo
|
此时,浏览器的显示效果为:
大家可以看到,我们通过使用 this.clickHandler4.bind(this, item.id, item.title)
这种形式来对 react
中的事件进行参数传递。
(4)注意点
React 16
将事件绑定到 document
上;
React 17
将事件绑定到 root
组件上;
- 这样做的好处在于:有利于多个
React
版本并存,例如微前端。
如下图所示:
5、表单
(1)input textarea select 用 value
先来看一段代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| 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
里面的值。
上面我们已经讲解了 input
,接下来我们来看 textarea
和 select
。
先来看 textarea
相关的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| 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> <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
。具体代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| 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> <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
。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| 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> <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
也是类似,如下代码所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| 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> 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
类型检查。
先来看一段代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
| 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: '' }) } }
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> } }
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 }
}
class TodoListDemo 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' } ], 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 要在构造函数中定义。如下代码所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| 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> </div> } }
export default StateDemo
|
第二点,不要直接修改 state ,要使用不可变值。如下代码所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| js复制代码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= () => { this.setState({ count: this.state.count + 1 }) } }
export default StateDemo
|
大家可以看到,在上面的代码中,我们通过 this.state({})
这种形式,来修改 state
的值。值得注意的是,很多小伙伴会直接使用 this.state.count++
来修改 state
的值,这在 react
中是非常不允许的。因此,要注意这个要点。
第三点,在 react
中操作数组的值。如下代码所示:
1 2 3 4 5 6 7 8 9 10 11
| 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 })
|
第四点,在 react
中操作对象的值。如下代码所示:
1 2 3 4 5 6
| js复制代码 this.setState({ obj1: Object.assign({}, this.state.obj1, {a: 100}), obj2: {...this.state.obj2, a: 100} })
|
(2)可能是异步更新
react
中的 state
,有可能是异步更新。来看一段代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| 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= () => { this.setState({ count: this.state.count + 1 }, () => { console.log('count by callback', this.state.count) }) console.log('count', this.state.count) } }
export default StateDemo
|
此时浏览器的显示效果为:
大家可以看到,this.state
前半部分并不能同一时间得到更新,所以它是异步操作。而后面的箭头函数中的内容可以得到同步更新,所以后面函数的部分是同步操作。
值得注意的是, setTimeout
在 setState
中是同步的。来看一段代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| 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(() => { this.setState({ count: this.state.count + 1 }) console.log('count in setTimeout', this.state.count) }, 0) } }
export default StateDemo
|
此时,浏览器的显示效果为:
还有一个要注意的点是,如果是自己定义的 DOM
事件,那么在 setState
中是同步的,用在 componentDidMount
中。
如果是销毁事件,那么用在 componentWillMount
生命周期中。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| 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() { document.body.addEventListener('click', this.bodyClickHandler) } componentWillUnmount() { document.body.removeEventListener('click', this.bodyClickHandler) } }
export default StateDemo
|
此时浏览器的显示效果为:
(3)可能会被合并
setState
在传入对象时,更新前会被合并。来看一段代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| 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= () => { 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
才是。但其实,如果传入的是对象,那么结果会把三个合并为一个,最终只执行一次。
还有另外一种情况,如果传入的是函数,那么结果不会被合并。来看一段代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| 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= () => { 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…
下面附上生命周期的图:
转至:React快速入门,一文弄懂react的基本使用和高级特性 - 掘金 (juejin.cn)