类组件的创建以及props和state
ES6方式的创建
import React from 'react'
import ReactDOM from 'react-dom'
class B extends React.Component{
constructor(props){
super(props)
}
render(){
return (
<div>hi</div>
)
}
}
export defalut B
但是需要注意的是,ES6的创建方式并不支持IE8等浏览器,可能需要用webpack+babel将其翻译成ES5即可。
有关props和state的内容可以看我的另外一篇博客
生命周期
什么是生命周期
类比如下代码:
let div = document.createElement('div')//这是div的create/construct过程
div.textContent = 'hi'//这是初始化state
document.body.appendChild(div)//这是div的mount的过程
div.textContent = 'hi2'//这是div的update过程
div.remove()//这是div的unmount的过程
React组件也有类似的过程,称之为生命周期
函数列表
constructor()
static getDerivedStateFromProps()
shouldComponentUpdate()
render()
getSnapshotBeforeUpdate()
componentDidMount()
componentDidUpdate()
componentWillUnmount()
static getDerivedStateFromError()
componentDidCatch()
其中比较重要的是
constructor()//在这里初始化state
shouldComponentUpdate()//return false阻止更新
render()//渲染,创建虚拟DOM
componentDidMount()//组件出现在页面
componentDidUpdate()//组件已更新
componentWillUnmount()//组件将移除
constructor
用途
初始化props
初始化state,但此时不能调用setState
用来写bind this如:
constructor(){
/*其他代码略*/
this.onClick = this.onClick.bind(this)
}
可以用新语法代替:
onClick = () =>{}
constructor(){/*其他代码省略*/}
也可以不写consturctor
shouldComponentUpdate
用途
返回true则表示不阻止UI更新
返回false则表示阻止UI更新
常见问题:shouldComponentUpdate有什么用
答:它允许我们手动判断是否进行组件更新,我们可以根据应用场景灵活地设置返回值,以免不必要的更新
示例:
如图中代码所示,点击事件触发后,n+1-1值是没有变化的,但是点击一次render触发一次。
但是加上shouldComponentUpdate后,如图
当新的state和就的state一致时,返回false取消更新,会发现无论怎么点击按钮,都只运行了一次render。
注意!shouldComponentUpdate(newProps,newState)的两个参数必须都要写,即使第一个不用,但是写来占位。
onClick时,n的值经过+1-1没有变化,但是生成了一个新的对象。新对象和旧对象的地址不同。
工作流程
没有shouldComponentUpdate(newProps,newState)时,更改数据后执行render生成新的虚拟DOM,与原来的对比进行局部的UI更新。但是加了shouldComponentUpdate(newProps,newState)后,发现数据没变,从render之前就截停了。节省了很多步骤。
收到它的启发,所有组件都可以用这种方式来进行优化,将newState和this.state每个属性进行对比。
此外React内置了一个功能叫做React.PureComponent可以代替React.Component
代码主体不变,只是加了Pure即可实现刚才一样的效果。
**PureComponent 会在 render 之前对比新 state 和旧 state 的每一个 key,以及新 props 和旧 props 的每一个 key。
如果所有 key 的值全都一样,就不会 render;如果有任何一个 key 的值不同,就会 render。它是一个浅对比,指挥对比第一层的属性**
render
用途
展示视图
return(<div>...</div>)
只能有一个根元素
如果有两个根元素需要用<React.Fragment>包起来,可以简写为<></>
技巧
-
render里面可以写if-else
-
render里面可以写?:表达式
-
render里面不能直接写for循环,需要用数组
-
render里面可以写array.map(循环)
示例:
实现点击+1当n是偶数时显示n是偶数,当n是奇数时显示n是奇数
可以用问号冒号表达式
state中有数组时,可以用array.map()进行遍历
render() {
return this.state.array.map(n=><span>{n}</span>)
componentDidMount
用途
在元素插入页面后执行,这些代码依赖DOM
例如想要获取div的高度,可以在这个生命周期函数内写
发起加载数据的AJAX请求(官方推荐)
首次渲染会执行此钩子
示例:
此外还可以用ref,这样可以避免id冲突的问题
componentDidUpdate
用途
视图更新后执行代码
**也可以发起AJAX请求,用于更新数据
首次渲染不会执行此钩子
注意:在此处的setState可能会引起无限循环,除非在if里
若`shouldComponentUpdate``返回false则不会渲染
componentDidUpdate(preProps,preState,snapshot)
componentWillUnmount
用途
组件将要被移除页面然后被销毁时执行的代码
unmount过的组件不会被mount
原则:谁污染谁治理
举例:
假如在componentDidMount内监听了window.scroll
你就要在componentWillUnmount内取消监听
假如在componentDidMount里创建了Timer
你就要在componentWillUnmount里取消Timer