一、简述React的生命周期
-
挂载mount
- construct(props)
- static getDerivedStateFromProps(props, state) 在每次组件被重新渲染之前调用,用于从props更新状态。
- render()
- componentDidMount() 在组件第一次渲染完成之后立即被调用。在这个方法中,可以执行操作DOM、数据请求或订阅等其他副作用。
-
更新update
- static getDerivedStateFromProps(props, state) 与挂载阶段相同,在每次渲染之前调用,用来根据props更新状态。
- shouldComponentUpdate(nextProps, nextState) 在接收到新的props或state的时候调用。
- render()
- getSnapshotBeforeUpdate(prevProps, prevState) 在更新被渲染到DOM之前被调用。此方法的返回值作为参数传递给componentDidUpdate。
- componentDidUpdate(prevProps, prevState, snapshot) 在更新完成并且DOM已经更新之后被调用。常用于处理更新后的副作用,如网络请求、DOM操作等。
-
卸载unmount
- componentWillUnmount()
-
错误处理 //16.8
- static getDerivedStateFromError(error) 当子组件抛出错误时调用,它可以用来更新组件的状态,以显示降级的UI。
- componentDidCatch(error, errorInfo) 当子组件抛出错误时调用,它可以用来记录错误信息。
二、React事件机制和原生DOM事件流的区别
React事件绑定在document上,原生事件绑定到dom上。因此相对于绑定位置来说,dom上的事件优先级高于document上的事件。
三、Redux工作原理
Redux遵循单项数据流。
四、mobx工作原理
mobx使用观察者模式,监听数据变化更新视图。
五、React hooks解决了什么问题
React hooks解决了函数组件没有状态的问题。
六、setState是同步还是异步的
在React 18之前,setState在同步里是异步的,在异步里是同步的。在React 18之后,通常认为setState是异步的,是同步调用,异步执行。
七、Fiber
Fiber是什么
Fiber是 React 16引入的新协调算法,优化了UI渲染过程
Fiber是在什么版本引入的,解决什么问题
Fiber是在React 16版本引入的,解决15版本的卡顿问题
Fiber解决卡顿的原理
Fiber在更新状态可中断,当浏览器遇到优先级更高的任务,可以优先执行,处理完成后,继续进行更新。
传统的 Reconciliation(协调)和 Fiber 架构相比,有什么不同?
传统的Reconciliation是同步、递归的,Fiber采用链表结构使渲染可以中断恢复。
Fiber的数据结构
主要五标签:tag
、key
、child
、sibling
、return
tag
:用来标识节点类型,比如函数式组件、类组件、DOM元素等。key
:唯一标识,用于兄弟元素之间建立唯一的身份。child
:指向第一个子节点,用于构建子节点的链表结构。sibling
:指向fiber节点的下一个兄弟节点。return
:指向父节点,用于构建父节点的链表结构。
Fiber的工作原理
fiber在内存中维护两棵树
current
树:当前渲染的树workInProgress
树:正在渲染的树
每次更新过程中,都会在内存中diff比对workInProgress
和新的vdom
,进而构建workInProgress
完全修改,完成workInProgress
之后,会将其赋值给current
树进行渲染。
- Reconciliation调和
Reconciliation
是指React将current
树和workInProgress
树进行diff操作,找出需要更新的节点,将节点标记上flags
。
- commit提交
commit
是指React将workInProgress
树应用到DOM中(更新current
),完成页面刷新。
Fiber的优点
- 更新过程可中断
- 更新过程可恢复
- 更新过程中可优先级排序
Fiber的缺点
- 更新过程复杂
- 更新过程更耗时
- 更新过程中需要维护两棵树
八、React的diff算法
此处只讲解React 16.8版本之后
- 首次渲染,不需要进行diff比对,直接将
vDOM
转化成Fiber
中的workInProgress
树,构建完成后,将其赋值给current
树,通知渲染器render
渲染。 - 后续渲染,将
新的VDOM
和旧的fiber
树进行diff比对。
diff比对流程
- 第一次遍历:将
新的VDOM
和旧的fiber
进行遍历,按照顺序查找,是否有可复用的节点,判断新的VDOM
是否遍历完成,如果遍历完成,删除旧的fiber
中的剩余节点,如果没有遍历完成,则进行二次遍历。 - 第二次遍历:将
旧的fiber
中的剩余节点放入Map中,然后遍历剩下的新的VDOM
,如果存在于Map中,则打上更新标签,遍历完成后,将剩余节点打上删除标签,新的VDOM
节点打上新增标签。
九、React在哪里捕获错误
官网例子:
javascript
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// 更新 state 使下一次渲染能够显示降级后的 UI
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// 你同样可以将错误日志上报给服务器
logErrorToMyService(error, errorInfo);
}
render() {
if (this.state.hasError) {
// 你可以自定义降级后的 UI 并渲染
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
使用
xml
<ErrorBoundary>
<MyWidget />
</ErrorBoundary>
但是错误边界不会捕获:
csharp
try{}catch(err){}
///异步代码(例如 setTimeout 或 requestAnimationFrame 回调函数)
///服务端渲染
///它自身抛出来的错误(并非它的子组件)
十、React组件传值有哪些方式
- 父传子 props
- redux
十一、React中函数(无状态)组件和类组件的区别
无状态组件不支持修改状态,只能展示
十二、React中如何做到vue中keep-active的缓存
使用了react-keep-active库
十三、React中几种创建组件的方式
- React.createClass
- 类组件
- 函数组件
十四、React中props和state有什么区别
- props上的属性是从父组件传递到子组件,子组件原则上是只读的,只能使用,不能修改。
- state上的属性是组件创建,可以使用、修改。
十五、React中keys的作用
key作为唯一标识,用于高效的diff比对。
十六、受控组件和非受控组件
- 受控组件的状态由变量控制。
- 非受控组件的状态不由变量控制。
js
// 受控组件
let value = ''
<input value={value} onChange={e => value = e.target.value}/>
十七、为什么虚拟dom会提高性能
虚拟dom相当于在js和真实dom中间增加了一层缓存,利用dom diff算法避免了很多没有必要的dom操作,从而提高性能。