什么是虚拟DOM?
虚拟 DOM (VDOM)是真实 DOM 在内存中的表示。UI 的表示形式保存在内存中,并与实际的 DOM 同步。这是一个发生在渲染函数被调用和元素在屏幕上显示之间的步骤,整个过程被称为调和。
React中的状态是什么?它是如何使用的
状态是 React 组件的核心,是数据的来源,必须尽可能简单。基本上状态是确定组件呈现和行为的对象。与props 不同,它们是可变的,并创建动态和交互式组件。可以通过 this.state()
访问它们。
虚拟 DOM 的引入与直接操作原生 DOM 相比,哪一个效率更高,为什么
虚拟DOM相对原生的DOM不一定是效率更高,如果只修改一个按钮的文案,那么虚拟 DOM 的操作无论如何都不可能比真实的 DOM 操作更快。在首次渲染大量DOM时,由于多了一层虚拟DOM的计算,虚拟DOM也会比innerHTML插入慢。它能保证性能下限,在真实DOM操作的时候进行针对性的优化时,还是更快的。所以要根据具体的场景进行探讨。
在整个 DOM 操作的演化过程中,其实主要矛盾并不在于性能,而在于开发者写得爽不爽,在于研发体验/研发效率。虚拟 DOM 不是别的,正是前端开发们为了追求更好的研发体验和研发效率而创造出来的高阶产物。虚拟 DOM 并不一定会带来更好的性能,React 官方也从来没有把虚拟 DOM 作为性能层面的卖点对外输出过。**虚拟 DOM 的优越之处在于,它能够在提供更爽、更高效的研发模式(也就是函数式的 UI 编程方式)的同时,仍然保持一个还不错的性能。
为什么 useState 要使用数组而不是对象
useState 的用法:
const [count, setCount] = useState(0)
复制代码
可以看到 useState 返回的是一个数组,那么为什么是返回数组而不是返回对象呢?
这里用到了解构赋值,所以先来看一下ES6 的解构赋值:
数组的解构赋值
const foo = [1, 2, 3];
const [one, two, three] = foo;
console.log(one); // 1
console.log(two); // 2
console.log(three); // 3
复制代码
对象的解构赋值
const user = {
id: 888,
name: "xiaoxin"
};
const {
id, name } = user;
console.log(id); // 888
console.log(name); // "xiaoxin"
复制代码
看完这两个例子,答案应该就出来了:
- 如果 useState 返回的是数组,那么使用者可以对数组中的元素命名,代码看起来也比较干净
- 如果 useState 返回的是对象,在解构对象的时候必须要和 useState 内部实现返回的对象同名,想要使用多次的话,必须得设置别名才能使用返回值
下面来看看如果 useState 返回对象的情况:
// 第一次使用
const {
state, setState } = useState(false);
// 第二次使用
const {
state: counter, setState: setCounter } = useState(0)
复制代码
这里可以看到,返回对象的使用方式还是挺麻烦的,更何况实际项目中会使用的更频繁。 总结:useState 返回的是 array 而不是 object 的原因就是为了降低使用的复杂度,返回数组的话可以直接根据顺序解构,而返回对象的话要想使用多次就需要定义别名了。
Redux 请求中间件如何处理并发
使用redux-Saga redux-saga是一个管理redux应用异步操作的中间件,用于代替 redux-thunk 的。它通过创建 Sagas 将所有异步操作逻辑存放在一个地方进行集中处理,以此将react中的同步操作与异步操作区分开来,以便于后期的管理与维护。 redux-saga如何处理并发:
- takeEvery
可以让多个 saga 任务并行被 fork 执行。
import {
fork,
take
} from "redux-saga/effects"
const takeEvery = (pattern, saga, ...args) => fork(function*() {
while (true) {
const action = yield take(pattern)
yield fork(saga, ...args.concat(action))
}
})
复制代码
- takeLatest
takeLatest 不允许多个 saga 任务并行地执行。一旦接收到新的发起的 action,它就会取消前面所有 fork 过的任务(如果这些任务还在执行的话)。
在处理 AJAX 请求的时候,如果只希望获取最后那个请求的响应, takeLatest 就会非常有用。
import {
cancel,
fork,
take
} from "redux-saga/effects"
const takeLatest = (pattern, saga, ...args) => fork(function*() {
let lastTask
while (true) {
const action = yield take(pattern)
if (lastTask) {
yield cancel(lastTask) // 如果任务已经结束,则 cancel 为空操作
}
lastTask = yield fork(saga, ...args