---
nav:
title: 面试
path: /interview
group:
title: 💊 面试题库
order: 6
---
# React
google 出品的一款前端MVC框架,将所有可视化模块组件化,提升开发效率,在前端界具有跨时代意义,目前居于三大框架之首。
## 为什么选择 react 框架,而不是原生js
1. 提升复用率,组件化的开发形式代码的复用率更高,交付更快,拓展性更强
2. 生态成熟,目前基于react的生态圈比较完善,可以更快提升开发的效率
3. 相比较早年的js + jq的开发形式,MVC结构能够更好的提升代码的易读性,让开发更加清晰
## 什么是 fiber 架构
react 需要经历两个阶段:
1. 将jsx转换成 AST 结构
2. 新老ast结构进行比较,让后更新渲染到页面上
16以前的版本是将更新渲染直接入栈出栈队列执行,diff算法本质上是一种递归,递归无法中断,这种形式可能会由于IO堵塞从而导致页面卡顿丢帧。
而fiber架构有效的改良了这一点,使用的是一种循环机制,将整个任务渲染切片成无数个小任务,发放到每个细分的时间节点中执行,优先处理最紧急的任务,有效降低了卡顿的情况发生。

## hooks 相比较传统 class 组件的区别
## 优点
1. 解决了 HOC 的嵌套问题,扁平式状态逻辑更加简洁
2. 解决了类组件的 this指向问题
3. 分割在不同生命周期的代码使得代码难以维护
4. 降低代码的复用成本,减少每个组件继承react.component,大大提升性能
## 缺点
1. 额外的学习成本
2. 没有类组件的生命周期,也就没办法和ComponentUpdate一样获取组件上的新旧数据做比较
## memo 和 PureComponent
理论上父组件状态更新,但是传递给子组件的内容没更新,子组件不应该重新渲染,memo 和 PureComponent 都是为了减少父组件的刷新导致子组件的额外渲染,区别是 memo 针对的是函数组件,PureComponent 针对的则是类组件。
```js
class Component extends React.PureComponent {
render() {
return (
类组件
)
}
}
const Component = React.memo(() => {
return (
函数组件
)
})
```
## useMeno
将计算结果缓存下来,一般使用在比较复杂的计算函数中,降低大量计算的时候时间和性能上的消耗。
```jsx
import React, { useMemo, useEffect, useState } from 'react'
export default () => {
const [data1, setData1] = useState(1)
const [data2, setData2] = useState(1)
const memo1 = useMemo(() => {
console.log('执行memo')
return data1
}, [data1])
const f2 = (() => {
console.log('执行f2')
return data2.toString()
})()
return (
{memo1}
{f2}
)
}
```
## useCallback
基本上和 useMemo 代码逻辑是一样的,只是useCallback 相比较 useMemo是将函数缓存下来,防止执行其他操作的时候多次渲染,消耗性能。需要搭配meno一起使用。
```jsx
import React, { useEffect, useCallback, useState } from 'react'
const Btn = React.memo((props) => {
const [txt1, setTxt1] = useState(0)
const [txt2, setTxt2] = useState(0)
useEffect(() => {
setTxt1(txt1 + 1)
},[props.fn1])
useEffect(() => {
setTxt2(txt2 + 1)
}, [props.fn2])
return (
使用了cb方法{txt1}
没使用cb方法{txt2}
)
})
export default () => {
const [data1, setData1] = useState(1)
const fn1 = useCallback(() => {
console.log('使用了回调缓存')
setData1(data1 + 1)
}, [])
const fn2 = () => {
setData1(data1 + 1)
}
return (
数据变化:{data1}
)
}
```
## lazy
懒加载组件,实现效果类似webpack 的 code spliting。
```js
import React, { lazy, Suspense } from 'react'
const Comp = React.lazy(() => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(import(/*webpackChunkName:"OtherComponent"*/'./OtherComponent'))
}, 2000)
})
});
export default () => {
return (
);
}
```
> 拓展:懒渲染可以参考 **react-visibility-observer** ,在页面滚动到可视范围时才加载相应的内容
## 列表使用key属性
首先我们需要知道react的virtualDom的原理,如果没有id作为标识的情况时,渲染引擎会直接将它视为新的标签,从而造成渲染的消耗,以下例子中,相比较添加了key属性来说,多了两次更新和一次新增的额外渲染。
```js
// 无key值
// 有key值
```
## componentDidMount 和 ComponentWillMount 区别
### componentWillMount
1. 将要装载,在render之前调用;
2. 可以在服务端被调用,也可以在浏览器端被调用;
3. componentWillMount 每一个组件render之前立即调用
### componentDidMount
1. render之后并不会立即调用,而是所有的子组件都render完之后才可以调用
2. 装载完成,在render之后调用
3. 只能在浏览器端被调用,在服务器端使用react的时候不会被调用
## 手写一个简单的 useState
```js
const [type, setType] = useState(1)
function useState(initData) {
let type = initData
let setType = (val) => {
type = val
}
return [
type,
setType
]
}
```
## redux 的工作原理
redux 分为几个重要的概念:1. store(容器)、2. state(数据)、3. action(动作)、4. reducer(计算动作过程)、5. dispatch(事件分发)
工作过程:dispatch通过调用action执行一个事件,store自动调用reducer对state进行变更,state变更,同时view也产生变化
## 参考文档
> https://juejin.cn/post/6844903922453200904