「这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战」
前情:换工作 + 换技术栈同时进行 QAQ
Virtual DOM
React把 真实DOM树 转换为 JavaScript对象树(VirtualDOM)。每次更新后,重新计算 Virtual DOM,并和上一次的进行对比,对发生变化的部分做批量更新。React也提供了 shouldComponentUpdate 生命周期函数,减少数据变化后不必要的对比过程,以保证性能。
优点:
- 提升性能,优化渲染方式
- 便于和其他平台集成(React-native、React-router-dom)
构建:
React通过创建和更新 虚拟元素virtual element 来管理整个 virtual DOM。
React创建的虚拟元素分为:
- DOM元素
<button class="btn btn-blue">
<em>confirm</em>
</button>
// ---- json --- virtual element ----
{
type: 'button',
props: {
className: 'btn btn-blue',
children: {
type: 'em',
props: {
children: 'confirm'
}
}
}
}
- 组件元素
const Button => ({ color, text }) {
return {
type: 'button',
props: {
className: `btn btn-${color}`,
children: {
type: 'em',
props: {
children: text
}
}
}
}
}
// ---- json --- virtual element --- Button('blue', 'Confirm') ----
{
type: 'Button',
props: {
color: 'blue',
text: 'Confirm'
}
}
组件声明
class声明组件
【ShopingList】React 组件类 / 组件类型。接受 props,通过 render 方法返回需要展示在屏幕上的视图的层次结构。
render方法的返回一个React元素,描述屏幕上看到的内容
class ShopingList extends React.Component {
state = {
value: '',
visible: false
}
handleVisible = (visible:boolean) => {
this.setState({ visible }, () => {
// 处理visible之后回调
});
};
render() {
const { message } = this.props;
const { value, visible } = this.state;
return {
<div>{message}</div>
}
}
}
export { ShopingList }
// 或者 React.PureComponent { .... }
React.PureComponent
与 React.Component 类似。React.PureComponent 通过浅层对比 prop 和 state 的方式,实现了 shouldComponentUpdate()
-
如果赋予 React组件 相同的 props 和 state,
render()函数会渲染相同的内容,那么在某些情况使用 pureComponent 可以提高性能 -
React.PureComponent中的shouldComponentUpdate()仅作对象的浅层比较,如果对象数据结构复杂,可能会因为无法检查深层变化导致错误。所以仅在数据结构简单时使用,或者深层数据结构发生变化的时候,使用forceUpdate()来确保组件更新 -
React.PureComponent中的shouldComponentUpdate()将跳过所有子组件树的 prop 更新,需要确保所有子组件也都使用React.PureComponent声明。
React.memo
高阶组件,和 React.PureComponent类型,但只适用于函数组件。
-
如果函数组件在给定 相同props 会渲染相同内容,那么可以将其包装在
memo中调用,通过 记忆组件 渲染结果的方式提高组件性能。(React 将跳过渲染组件,直接复用最近一次渲染的结果) -
memo仅检查props变更。如果函数组件被memo包裹,且实现过程中出现useState和useContext的hook,那么当context发生变化时,仍会触发重新渲染 -
默认情况仅对复杂对象做浅层对比,如果需要控制比对过程,需要传入第二个参数(自定义比较函数)
const Animal = React.memo(function Animal(props) {
// 使用props渲染
})
// --------- 自定义函数 ------------
function Animal(props) {
// 使用props渲染
}
function areEqual(prevProps, nextProps) {
// 自定义比对:return 两个传参 render方法 返回结果是否相同(true/false)
}
export default React.memo(Animal, areEqual)
React.FC
const ShopingList: React.FunctionComponent<{message:string}> = (props: any) => {
const { visible } = props;
const handleVisible = (props:any) => {
// ....
}
return ( <div>{message}</div> )
};
// FunctionComponent 简写成 FC
const ShopingList: React.FC<{ message:string}> = ({ message }) => (
<div>{message}</div>
);
对比三种组件创建方式:
-
React.Component通用的创建方式,万能但不能提高组件性能 -
React.PureComponent浅层对比判断shouldComponentsUpdate。传入相同props和state不触发组件更新。针对传入简单数据类型的props和state使用,或使用forceUpdate强制触发更新。 -
React.memo记忆组件,仅针对函数组件。相同props将会直接使用最近一次渲染结果,不触发更新。针对传入简单数据类型的props使用,或者传入第二个参数作为自定义比较函数。
以上三种都是class组件,可以认为是一种声明方式,只是使用了不同的React方法,区别在于方法内对组件重新渲染节点的优化。
函数组件
接受唯一带有数据的props对象,并返回一个react元素。本质上是 js函数
function welcome(props) {
return <h1>Hello, {props.name}</h1>
}
---- 写在代码 -- 箭头函数 -----
export default (props) => {
return ( ... )
}
不知道怎么用就用函数组件!!!先把代码码出来再管优化。
渲染组件
自定义组件必须以大写字母开头
function Welcome(props) {
return <h1>Hello, {props.name}</h1>
}
const element = <Welcome name="Sara"/>
ReactDOM.render(
element,
document.getElementById('root')
)
/*
1. 调用 ReactDOM.render() 函数,并传入 Welcome组件 作为参数
2. React调用 Welcome组件,并将 { name: 'Sara' } 作为 props 传入
3. Welcome组件 将 h1元素 作为返回值
4. React DOM 将 DOM 更新为 <h1>Hello, Sara</h1>
*/