0. 前言
前段时间,实习生面试发现自己对于React某些知识点不是很熟悉。因此,小编花了一天的时间整理了一下相关的知识点。这篇文章记录了小编的整理结果。这篇文章主要包含三个内容:React Hook、React 生命周期,以及React 函数组件和类组件的区别。
1. React Hook
React的官网对于Hook是这样介绍的:
Hook 是 React16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
在这篇文章的第一部分,我们就来看一看Hook相关的内容。
1.1 为什么要使用Hook?
- 方便组件之间服用状态逻辑:在没有 Hook 时,React内有提供将可复用性行为“附加”到组建的途径。Hook使得在无需修改组件结构的情况下复用状态逻辑
- 方便理解复杂组件:Hook将组件中相互关联的部分拆分成更小的函数,而并非强制按照生命周期来划分,可以使得组件的内部状态变得更加可预测。
- 难以理解的class:在非 class 的情况下可以使用更多的 React 特性。Hook提供了解决函数组件中添加状态和调用其生命周期的问题。
1.2 常用的Hook整理
useState():通过在函数组件中调用它来给组件添加一些内部state.useState()会返回一对值:当前状态和让它更新的函数。它的用法类似于 class 组建的this.state().不同的是state只能声明一次,而Hook则可以多次使用。使用方法如下:
import React, { useState } from 'react';
function Example() {
// 声明一个叫 "count" 的 state 变量 const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
useEffect():是一个Effect Hook,给函数组件增加了操作副作用的能力。它跟class组件中的componentDidMount、componentDidUpdate,以及componentWillUnmount具有相同的用途,只不过合并成了一个API。当你使用useEffect时,就是告诉React在完成DOM的更改后运行你的副作用函数。使用方法如下:
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
这段代码的功能是在componentDidMount这个生命周期中改变文档的title属性。
useContext():跨足间共享数据的钩子函数。这个钩子函数跟context这个属性相关。对于context属性而言,一定会有一个context的生产者和消费者(使用者)。生产者使用React.createContext()方法来创建context;而消费者使用useContext这个钩子函数来使用它。在类组件中,使用context属性,需要在contextType中传入需要使用到的context属性名称。函数组件的使用方法如下:
const themes = {
light: {
foreground: "#000000",
background: "#eeeeee"
},
dark: {
foreground: "#ffffff",
background: "#222222"
}
};
const ThemeContext = React.createContext(themes.light);
function App() {
return (
<ThemeContext.Provider value={themes.dark}>
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar(props) {
return (
<div>
<ThemedButton />
</div>
);
}
function ThemedButton() {
const theme = useContext(ThemeContext);
return (
<button style={{ background: theme.background, color: theme.foreground }}>
I am styled by theme context!
</button>
);
}
useReducer():useState的替代方案,类似于redux中的写法。使用方法如下:
const initialState = {count: 0};
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
</>
);
}
useRef():获取组件的实例。返回一个可变的ref对象。Ref时访问DOM节点或在render中创建React元素的方式。即在声明周期之外有第三方操作的处理工具。使用方法如下:
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// `current` 指向已挂载到 DOM 上的文本输入元素
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
useMemo()和useCallback():useMemo缓存数据,useCallback缓存函数。
1.3 Hook 分类
可以将Hook分为三类:
- 输入:useState,useContext,useReducer
- 输出:useEffect,useMemo和useCallback
- 其他:useRef
1.4 用Hook模拟React生命周期
- componentDidMount:第二个参数为空数组可以模拟componentDidMount
useEffect(() => {
console.log('第一次渲染使用')
},[])
- componentDidUpdate:利用Ref创建表示是否是第一次调用的对象,然后进行判断。没有第二个参数表示监听所有属性;监听多个属性的变化需要将属性作为数组传入第二个参数。
const mounted = useRef()
useEffect(() => {
if(!mounted) {
mounted = true
} else {
console.log('组件更新使用')
}
})
- componentWillUnmount:组件卸载时需要清除Effect创建的订阅,定时器等资源。useEffect返回的函数可以表示组件已死亡。
useEffect(() => {
return () => {
console.log('组件已死亡')
}
}, [])
2. React 生命周期
从广义上讲,分为三个阶段:挂载、渲染、卸载。具体如下:
其中重要的阶段有:
- 挂载阶段:componentWillMount、componentDidMount,render
- 运行阶段:componentWillUpdate、render、componentDidUpdate
- 卸载阶段:componentWillUnmount
在React的新版本中取消了三个阶段,新增了两个阶段:
- 取消的:componentWillMount、componentWillReceiveProps、componentWillUpdate
- 新增的:getDerivedStateFromProps、getSnapshotBeforeUpdate
3. React FunctionComponent 和 ClassComponent 的区别
- 类组件定义函数需要绑定this,函数组件不需要
- 类组件有生命周期,函数组件没有
- 类组件有状态state属性,并且可以根据这个属性进行条件渲染,函数组件没有
- props传参的差异,函数组件的props是作为参数传递进来的,因此中间不能改变;而类组件的props是作为类的一个属性传递的,在执行时可以随时改变这个属性。