zhangxk-notes

写 React / Vue 项目时为什么要在列表组件中写 key

不带有 key,并且使用简单的模板,基于这个前提下,可以更有效的复用节点,diff 速度来看也是不带 key 更加快速的,因为带 key 在增删节点上有耗时。这就是 vue 文档所说的默认模式。但是这个并不是 key 作用,而是没有 key 的情况下可以对节点就地复用,提高性能。

这种模式会带来一些隐藏的副作用,比如可能不会产生过渡效果,或者在某些节点有绑定数据(表单)状态,会出现状态错位。

key 是给每一个 vnode 的唯一 id,可以依靠 key,更准确, 更快的拿到 oldVnode 中对应的 vnode 节点。

利用 key 的唯一性生成 map 对象来获取对应节点,比遍历方式更快。

Vue VS React

使用场景

Vue 最适合解决短期的小型的问题,快速迭代的项目。它的体积小巧。React 更偏向于构建稳定大型的应用,非常的科班化。相比之下,Vue 更偏向于简单迅速的解决问题,更灵活,不那么严格遵循条条框框。因此也会给人一种大型项目用 React,小型项目用 Vue 的感觉。

模板

在 React 中,所有的组件的渲染功能一般依靠 JSX。Vue 使用 Templates。

(JSX) 你可以使用完整的编程语言 JavaScript 功能来构建你的视图页面。比如你可以使用临时变量、JS 自带的流程控制、以及直接引用当前 JS 作用域中的值等等。

事实上 Vue 也提供了渲染函数,甚至支持 JSX。然而,vue 推荐的还是模板。

模板比起 JSX 读写起来更自然。基于 HTML 的模板使得将已有的应用逐步迁移到 Vue 更为容易。 更抽象一点来看,我们可以把组件区分为两类:一类是偏视图表现的 (presentational),一类则是偏逻辑的 (logical)。我们推荐在前者中使用模板,在后者中使用 JSX 或渲染函数。

React 是在组件 JS 代码中,通过原生 JS 实现模板中的常见语法,比如插值,条件,循环等,都是通过 JS 语法实现的,更加纯粹更加原生。而 Vue 是在和组件 JS 代码分离的单独的模板中,通过指令来实现的,比如条件语句就需要 v-if 来实现对这一点,这样的做法显得有些独特,会把 HTML 弄得很乱。

React 中没有“槽”(slot)这一概念的限制,你可以将任何东西作为 props 进行传递。Vue 使用“槽”,定义了槽的使用规则。

样式

CSS 作用域在 React 中是通过 CSS-in-JS 的方案实现的。这里 React 和 Vue 主要的区别是,Vue 设置样式的默认方法是单文件组件里类似 style 的标签。

更新状态

在 React 应用中,当某个组件的状态发生变化时,它会以该组件为根,重新渲染整个组件子树。如要避免不必要的子组件的重渲染,你需要在所有可能的地方使用 PureComponent,或是手动实现 shouldComponentUpdate 方法。在 Vue 应用中,组件的依赖是在渲染过程中自动追踪的,所以系统能精确知晓哪个组件确实需要被重渲染。你可以理解为每一个组件都已经自动获得了 shouldComponentUpdate,并且没有上述的子树问题限制。

React.memo 是一个高阶组件,类似于 React.PureComponent,只不过用于函数组件而非 class 组件。 如果你的函数组件在相同 props 下渲染出相同结果,你可以把它包裹在 React.memo 中来通过缓存渲染结果来实现性能优化。这意味着 React 会跳过组件渲染,而使用上次渲染结果。 React.memo 默认只会浅比较 props,如果需要定制比较,你可以给第二个参数传入自定义比较函数

function MyComponent(props) {
  /* render using props */
}
function areEqual(prevProps, nextProps) {
  /*
  return true if passing nextProps to render would return
  the same result as passing prevProps to render,
  otherwise return false
  */
}
export default React.memo(MyComponent, areEqual);

监听数据变化的实现原理不同

Vue 通过 getter/setter 以及一些函数的劫持,能精确知道数据变化。React 默认是通过比较引用的方式(diff)进行的,如果不优化可能导致大量不必要的 VDOM 的重新渲染。

这是因为 Vue 和 React 设计理念上的区别,Vue 使用的是可变数据,而 React 更强调数据的不可变,两者没有好坏之分,Vue 更加简单,而 React 构建大型应用的时候更加合适。

Vue3.0 里为什么要用 Proxy API 替代 defineProperty API

defineProperty API 的问题:

Proxy API:

HoC 和 mixins

事件

React 组件绑定事件的本质是代理到 document 上。Vue 的事件挂载到真实的 DOM 节点。

react 自己定了一个 event 对象,存放着 onClick 回调们,在用户触发点击点击事件时,挨个检查并执行。

组件声明周期

Vue

React

为什么不可变性在 React 中非常重要

JSX

Babel 会把 JSX 转译成一个名为 React.createElement() 函数调用。React.createElement(type, props, children)

React 中 setState

原因: 在 ReactsetState 函数实现中,会根据一个变量 isBatchingUpdates 判断是直接更新 this.state 还是放到队列中回头再说,而 isBatchingUpdates 默认是 false,也就表示 setState 会同步更新 this.state,但是,有一个函数 batchedUpdates,这个函数会把 isBatchingUpdates 修改为 true,而当 React 在调用事件处理函数之前就会调用这个 batchedUpdates,造成的后果,就是由 React 控制的事件处理过程 setState 不会同步更新 this.state

好处:可以通过避免不必要的重新渲染来提升性能。

跨级传递数据的能力

React:Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。

Vue:provide 选项允许我们指定我们想要提供给后代组件的数据/方法,然后在任何后代组件里,我们都可以使用 inject 选项来接收指定的我们想要添加在这个实例上的 property。

React 中的错误边界

如果一个 class 组件中定义了 static getDerivedStateFromError()componentDidCatch() 这两个生命周期方法中的任意一个(或两个)时,那么它就变成一个错误边界。当抛出错误后,请使用 static getDerivedStateFromError() 渲染备用 UI ,使用 componentDidCatch() 打印错误信息。

Effect Hook

如果你熟悉 React class 的生命周期函数,你可以把 useEffect Hook 看做 componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个函数的组合。

在 React 更新 DOM 之后运行一些额外的代码( effect 发生在“渲染之后”)。默认情况下,它在第一次渲染之后和每次更新之后都会执行。如果 effect 返回一个函数,React 将会在执行清除操作时调用它,用来解绑事件(组件卸载的时候)。第二个参数用数组,可以指定哪些数据变化后运行函数。如果想执行只运行一次的 effect(仅在组件挂载和卸载时执行),可以传递一个空数组([])作为第二个参数。

node.js

跟踪回调路径

import { AsyncLocalStorage } from 'async_hooks';
const traceContext = new AsyncLocalStorage<string>();
export default traceContext;

// 起始函数中,注入 traceId
traceContext.run(traceId, next);

// 在回调中获取 traceId
export function getTraceId() {
  return traceContext.getStore();
}

nest.js

优点

生命周期

一般来说,一个请求流经中间件、守卫与拦截器,然后到达管道,并最终回到拦截器中的返回路径中(从而产生响应)。

diff 算法

通过两个假设,将传统的 diff 算法的复杂度从 O(n^3)降至 O(n)。

  1. 两个不同类型的元素会产生出不同的树;
  2. 开发者可以通过设置 key 属性,来告知渲染哪些子元素在不同的渲染下可以保存不变;