2022年React面试题
1. 什么是虚拟DOM
虚拟 DOM (VDOM)是真实 DOM 在内存中的表示。UI 的表示形式保存在内存中,并与实际的 DOM 同步。这是一个发生在渲染函数被调用和元素在屏幕上显示之间的步骤,整个过程被称为调和。
2. 类组件和函数组件之间的区别是啥?
- 类组件可以使用其他特性,如状态
state
和生命周期钩子。 - 当组件只是接收
props
渲染到页面时,就是无状态组件,就属于函数组件,也被称为哑组件或展示组件。
函数组件和类组件当然是有区别的,而且函数组件的性能比类组件的性能要高,因为类组件使用的时候要实例化,而函数组件直接执行函数取返回结果即可。为了提高性能,尽量使用函数组件。
区别 | 函数组件 | 类组件 |
---|---|---|
是否有 | 没有 | 有 |
是否有生命周期 | 没有 | 有 |
是否有状态 | 没有 | 有 |
3. React 中 refs 干嘛用的?
refs
提供了一种访问在render
方法中创建的 DOM 节点或者 React 元素的方法。在典型的数据流中,props
是父子组件交互的唯一方式,想要修改子组件,需要使用新的props
重新渲染它。凡事有例外,某些情况下咱们需要在典型数据流外,强制修改子代,这个时候可以使用Refs
。
4. React 组件生命周期有哪些不同阶段?
componentWillMount
:在渲染之前执行,用于根组件中的 App 级配置。componentDidMount
:在第一次渲染之后执行,可以在这里做AJAX请求,DOM 的操作或状态更新以及设置事件监听器。componentWillReceiveProps
:在初始化render
的时候不会执行,它会在组件接受到新的状态(Props)时被触发,一般用于父组件状态更新时子组件的重新渲染shouldComponentUpdate
:确定是否更新组件。默认情况下,它返回true
。如果确定在state
或props
更新后组件不需要在重新渲染,则可以返回false
,这是一个提高性能的方法。componentWillUpdate
:在shouldComponentUpdate
返回true
确定要更新组件之前件之前执行。componentDidUpdate
:它主要用于更新DOM以响应porps
或state
更改。componentWillUnmount
:它用于取消任何的网络请求,或删除与组件关联的所有事件监听器。
5. React 常用的hook
useState \ useEffect\ useContext \ useReducer \ useCallback \ useImperativeHandle \ useMemo \ useRef
6. React 组件间有那些通信方式?
- 父组件向子组件通信
- 通过 props 传递
- 子组件向父组件通信
- 主动调用通过 props 传过来的方法,并将想要传递的信息,作为参数,传递到父组件的作用域中
- 跨层级通信
- 使用 react 自带的 Context 进行通信,createContext 创建上下文, useContext 使用上下文。
参考下面代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40import React, { createContext, useContext } from 'react';
const themes = {
light: {
foreground: "#000000",
background: "#eeeeee"
},
dark: {
foreground: "#ffffff",
background: "#222222"
}
};
const ThemeContext = createContext(themes.light);
function App() {
return (
<ThemeContext.Provider value={themes.dark}>
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar() {
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>
);
}
export default App; - 使用 Redux 或者 Mobx 等状态管理库
- 使用订阅发布模式
- 使用 react 自带的 Context 进行通信,createContext 创建上下文, useContext 使用上下文。
7. 为什么 React 元素有一个 $$typeof 属性?
目的是为了防止 XSS 攻击。因为 Synbol 无法被序列化,所以 React 可以通过有没有 $$typeof 属性来断出当前的 element 对象是从数据库来的还是自己生成的。
如果没有 $$typeof 这个属性,react 会拒绝处理该元素。
相关阅读:为什么React元素有一个$$typeof属性?
8. 为什么 JSX 中的组件名要以大写字母开头?
因为 React 要知道当前渲染的是组件还是 HTML 元素。
9. redux 是什么?
Redux 是一个为 JavaScript 应用设计的,可预测的状态容器。
- 它解决了如下问题:
- 跨层级组件之间的数据传递变得很容易
- 所有对状态的改变都需要 dispatch,使得整个数据的改变可追踪,方便排查问题。
- 但是它也有缺点:
- 概念偏多,理解起来不容易
- 样板代码太多
10. setState到底是异步还是同步?
先给出答案: 有时表现出异步,有时表现出同步
setState
只在合成事件和钩子函数中是“异步”的,在原生事件和setTimeout
中都是同步的setState
的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形成了所谓的“异步”,当然可以通过第二个参数setState(partialState, callback)
中的callback拿到更新后的结果setState
的批量更新优化也是建立在“异步”(合成事件、钩子函数)之上的,在原生事件和setTimeout 中不会批量更新,在“异步”中如果对同一个值进行多次setState
,setState
的批量更新策略会对其进行覆盖,取最后一次的执行,如果是同时setState
多个不同的值,在更新时会对其进行合并批量更新
11.什么是跨域?如何解决跨域问题?
浏览器对于javascript的同源策略的限制。
- 域名不同 www.jd.com 与 www.taobao.com
- 端口不同 www.jd.com:8080 与 www.jd.com:8081
- 二级域名不同 item.jd.com 与 miaosha.jd.com
- http和https也属于跨域
解决跨域问题的方案
- Jsonp
最早的解决方案,利用script标签可以跨域的原理实现。
限制:
需要服务的支持
只能发起GET请求 - nginx反向代理
思路是:利用nginx把跨域反向代理为不跨域,支持各种请求方式
缺点:需要在nginx进行额外配置,语义不清晰 - CORS
规范化的跨域请求解决方案,安全可靠。
优势:
在服务端进行控制是否允许跨域,可自定义规则
支持各种请求方式
缺点:
会产生额外的请求
如果服务器允许跨域,需要在返回的响应头中携带下面信息:Access-Control-Allow-Origin:允许哪个域名进行跨域,是一个具体域名或者*(代表任意域名)1
2
3Access-Control-Allow-Origin: http://manage.handou.com
Access-Control-Allow-Credentials: true
Content-Type: text/html; charset=utf-8
Access-Control-Allow-Credentials:是否允许携带cookie,默认情况下,cors不会携带cookie,除非这个值是true
要想操作cookie,需要满足3个条件:
服务的响应头中需要携带Access-Control-Allow-Credentials并且为true。
浏览器发起ajax需要指定withCredentials 为true
响应头中的Access-Control-Allow-Origin一定不能为*,必须是指定的域名