美文网首页react & vue & angular
react18文档要点记录

react18文档要点记录

作者: 海豚先生的博客 | 来源:发表于2023-07-26 17:43 被阅读0次

描述UI

  • React 组件是一段可以 使用标签进行扩展 的 JavaScript 函数。
  • React 组件是常规的 JavaScript 函数,但 组件的名称必须以大写字母开头
  • 同一文件中,有且仅有一个默认导出,但可以有多个具名导出!
  • 为什么需要一个根标签
    • JSX 虽然看起来很像 HTML,但在底层其实被转化为了 JavaScript 对象,你不能在一个函数中返回多个对象,除非用一个数组把他们包装起来。这就是为什么多个 JSX 标签必须要用一个父元素或者 Fragment 来包裹。
  • 切勿将数字放在 && 左侧.左侧为0则会渲染为0
  • key 需要满足的条件
    • key 值在兄弟节点之间必须是唯一的。 不过不要求全局唯一,在不同的数组中可以使用相同的 key。
    • key 值不能改变,否则就失去了使用 key 的意义!所以千万不要在渲染时动态地生成 key。
  • 为什么需要key
    • React 里需要 key 和文件夹里的文件需要有文件名的道理是类似的。一个精心选择的 key 值所能提供的信息远远不止于这个元素在数组中的位置。即使元素的位置在渲染的过程中发生了改变,它提供的 key 值也能让 React 在整个生命周期中一直认得它。
    • 请不要在运行过程中动态地产生 key,像是 key={Math.random()} 这种方式。这会导致每次重新渲染后的 key 值都不一样,从而使得所有的组件和 DOM 元素每次都要重新创建。这不仅会造成运行变慢的问题,更有可能导致用户输入的丢失。
  • 纯函数的基本定义:
    • 只负责自己的任务。 它不会更改在该函数调用前就已存在的对象或变量。
    • 输入相同,输出也相同。 在输入相同的情况下,对纯函数来说应总是返回相同的结果。
  • React 假设你编写的所有组件都是纯函数。React 的渲染过程必须自始至终是纯粹的。组件应该只 返回 它们的 JSX,而不 改变 在渲染前,就已存在的任何对象或变量 — 这将会使它们变得不纯粹!
  • React 提供了 “严格模式”,在严格模式下开发时,它将会调用每个组件函数两次。通过重复调用组件函数,严格模式有助于找到违反这些规则的组件。
  • 副作用:包括更新屏幕、启动动画、更改数据等,它们被称为 副作用。它们是 “额外” 发生的事情,与渲染过程无关。
  • 在 React 中,副作用通常属于 事件处理程序。事件处理程序是 React 在你执行某些操作(如单击按钮)时运行的函数。即使事件处理程序是在你的组件 内部 定义的,它们也不会在渲染期间运行! 因此事件处理程序无需是纯函数
  • 如果你用尽一切办法,仍无法为副作用找到合适的事件处理程序,你还可以调用组件中的 useEffect 方法将其附加到返回的 JSX 中。这会告诉 React 在渲染结束后执行它。然而,这种方法应该是你最后的手段

添加交互

  • 事件处理函数是执行副作用的最佳位置,数据的改变使用state存储
  • 为什么需要useState
    • 局部变量无法在多次渲染中持久保存。当 React 再次渲染这个组件时,它会从头开始渲染——不会考虑之前对局部变量的任何更改。
    • 更改局部变量不会触发渲染。 React 没有意识到它需要使用新数据再次渲染组件。
  • Hooks ——以 use 开头的函数——只能在组件或自定义 Hook 的最顶层调用。
  • 如果你渲染同一个组件两次,每个副本都会有完全隔离的 state
  • React 把更改提交到 DOM 上
    • 对于初次渲染, React 会使用 appendChild() DOM API 将其创建的所有 DOM 节点放在屏幕上。
    • 对于重渲染, React 将应用最少的必要操作(在渲染时计算!),以使得 DOM 与最新的渲染输出相互匹配。
  • React 仅在渲染之间存在差异时才会更改 DOM 节点
  • 在渲染完成并且 React 更新 DOM 之后,浏览器就会重新绘制屏幕
  • 在一个 React 应用中一次屏幕更新都会发生以下三个步骤:
    1. 触发
    • 组件的 初次渲染。
    • 组件(或者其祖先之一)的 状态发生了改变
    1. 渲染。在您触发渲染后,React 会调用您的组件来确定要在屏幕上显示的内容。“渲染中” 即 React 在调用您的组件。
    • 在进行初次渲染时, React 会调用根组件。
    • 对于后续的渲染, React 会调用内部状态更新触发了渲染的函数组件。
    1. 提交。在渲染(调用)您的组件之后,React 将会修改 DOM。
    • 对于初次渲染, React 会使用 appendChild() DOM API 将其创建的所有 DOM 节点放在屏幕上。
    • 对于重渲染, React 将应用最少的必要操作(在渲染时计算!),以使得 DOM 与最新的渲染输出相互匹配。
  • 设置 state 会触发渲染(当你调用 useState 时)
  • 渲染会及时生成一张快照
    • “正在渲染” 就意味着 React 正在调用你的组件——一个函数。你从该函数返回的 JSX 就像是 UI 的一张及时的快照。它的 props、事件处理函数和内部变量都是 根据当前渲染时的 state 被计算出来的。
    • 返回的 UI “快照”是可交互的。它其中包括类似事件处理函数的逻辑,这些逻辑用于指定如何对输入作出响应。React 随后会更新屏幕来匹配这张快照,并绑定事件处理函数。因此,按下按钮就会触发你 JSX 中的点击事件处理函数。
    • state 实际上“活”在 React 本身中——就像被摆在一个架子上!——位于你的函数之外。当 React 调用你的组件时,它会为特定的那一次渲染提供一张 state 快照。你的组件会在其 JSX 中返回一张包含一整套新的 props 和事件处理函数的 UI 快照 ,其中所有的值都是 根据那一次渲染中 state 的值 被计算出来的!
  • 设置 state 只会为下一次渲染变更 state 的值。
  • 一个 state 变量的值永远不会在一次渲染的内部发生变化, 即使其事件处理函数的代码是异步的。
  • React 会使 state 的值始终”固定“在一次渲染的各个事件处理函数内部。 你无需担心代码运行时 state 是否发生了变化。
  • 变量和事件处理函数不会在重渲染中“存活”。每个渲染都有自己的事件处理函数。
  • 每个渲染(以及其中的函数)始终“看到”的是 React 提供给这个 渲染的 state 快照。
  • 过去创建的事件处理函数拥有的是创建它们的那次渲染中的 state 值。
  • React 会等到事件处理函数中的 所有 代码都运行完毕再处理你的 state 更新。
  • 在下次渲染前多次更新同一个 state,需要传入一个更新函数,如setNumber(n => n + 1),而不是像 setNumber(number + 1) 这样传入 下一个 state 值
  • 设置 state 不会更改现有渲染中的变量,但会请求一次新的渲染。
  • React 会在事件处理函数执行完成之后处理 state 更新。这被称为批处理。
  • 要在一个事件中多次更新某些 state,你可以使用 setNumber(n => n + 1) 更新函数。
  • 把所有存放在 state 中的 JavaScript 对象都视为只读的
  • 不要直接修改一个对象,而要为它创建一个 新 版本,并通过把 state 设置成这个新版本来触发重新渲染。
  • 你可以使用这样的 {...obj, something: 'newValue'} 对象展开语法来创建对象的拷贝。

状态管理

  • 只要一个组件还被渲染在 UI 树的相同位置,React 就会保留它的 state。 如果它被移除,或者一个不同的组件被渲染在相同的位置,那么 React 就会丢掉它的 state。
  • 相同位置的相同组件会使得 state 被保留下来
  • 对 React 来说重要的是组件在 UI 树中的位置,而不是在 JSX 中的位置!
  • 当你在相同位置渲染不同的组件时,组件的整个子树都会被重置
  • 永远要将组件定义在最上层(函数组件外)并且不要把它们的定义嵌套起来,否则每次渲染出的都是不同的组件,状态会丢失
  • 在相同位置重置 state
    1. 将组件渲染在不同的位置。同一个组件在第一个位置与第二个位置交替展示时会重置state
    2. 使用 key 来重置 state。即使两个 <Counter /> 会出现在 JSX 中的同一个位置,它们也不会共享 state
    • 使用key后,React 将重新创建 DOM 元素,而不是复用它们。
  • 为被移除的组件保留 state
    1. 用 CSS 把其他组件隐藏起来。这些组件就不会从树中被移除了,所以它们的内部 state 会被保留下来。这种解决方法对于简单 UI 非常有效。但如果要隐藏的树形结构很大且包含了大量的 DOM 节点,那么性能就会变得很差。
    2. 你可以进行状态提升并在父组件中保存每个收件人的草稿消息。这是最常见的解决方法
    3. 你也可以使用localStorage存储草稿信息
    4. 为多个 不同位置的 相同组件 指定key可以保留state
  • 把 useState 转化为 useReducer:
    1. 通过事件处理函数 dispatch actions(派发action对象);
    2. 编写一个 reducer 函数,它接受传入的 state 和一个 action对象(通常包含type字段),并返回一个新的 state;
    3. 使用 useReducer 替换 useState;
  • reducer 必须是一个纯函数——它应该只计算下一个状态。而不应该 “做” 其它事情,包括向用户显示消息。这应该在事件处理程序中处理。(为了便于捕获这样的错误,React 会在严格模式下多次调用你的 reducer。
  • Context 可以让父节点,甚至是很远的父节点都可以为其内部的整个组件树提供数据。
    1. 通过 export const MyContext = createContext(defaultValue) 创建并导出 context。
    2. 在无论层级多深的任何子组件中,把 context 传递给 useContext(MyContext) Hook 来读取它。
    3. 在父组件中把 children 包在 <MyContext.Provider value={...}> 中来提供 context。
  • 在 React 中,覆盖来自上层的某些 context 的唯一方法是将子组件包裹到一个提供不同值的 context provider 中。
  • 不同的 React context 不会覆盖彼此。你通过 createContext() 创建的每个 context 都和其他 context 完全分离,只有使用和提供 那个特定的 context 的组件才会联系在一起。一个组件可以轻松地使用或者提供许多不同的 context。

应急方案

  • 当你希望组件“记住”某些信息,但又不想让这些信息触发新的渲染时,你可以使用 ref
  • 当一条信息用于渲染时,将它保存在 state 中。当一条信息仅被事件处理器需要,并且更改它不需要重新渲染时,使用 ref 可能会更高效。
  • 何时使用ref
    • 存储timeout ID
    • 存储和操作DOM 元素
    • 存储不需要被用来计算 JSX 的其他对象。
    • 不要在渲染过程中读取或写入 ref.current,ref 本身是一个普通的 JavaScript 对象
  • 未给知长度的列表中每项绑定ref
    • 将函数传递给 ref 属性。这称为 ref 回调。当需要设置 ref 时,React 将传入 DOM 节点来调用你的 ref 回调,并在需要清除它时传入 null 。这使你可以维护自己的数组或 Map,并通过其索引或某种类型的 ID 访问任何 ref。
  • 访问另一个组件的 DOM 节点
    • 一个组件可以指定将它的 ref “转发”给一个子组件,子组件是使用 forwardRef 声明的。 这让从父组件接收的ref作为第二个参数传入组件,第一个参数是 props
  • 使用ref后,父组件可以调用子组件dom节点的所有方法,使用命令句柄(useImperativeHandle)可以只暴露一部分 API
  • 通常,你将从事件处理器访问 refs。
  • 你可以强制 React 同步更新(“刷新”)DOM。 为此,从 react-dom 导入 flushSync 并将 state 更新包裹 到 flushSync 调用中

相关文章

网友评论

    本文标题:react18文档要点记录

    本文链接:https://www.haomeiwen.com/subject/thzqudtx.html