• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

React hooks文档笔记二 添加交互性

武飞扬头像
你脸上有BUG
帮助1

1. 事件传播

js的事件流

  • 事件捕获:从外到内
  • 事件冒泡:从内到外(默认模式)
export default function Toolbar() {
  return (
    <div className="Toolbar" onClick={() => {
      alert('You clicked on the toolbar!');
    }}>
      <button onClick={() => alert('Playing!')}>
        Play Movie
      </button>
      <button onClick={() => alert('Uploading!')}>
        Upload Image
      </button>
    </div>
  );
}

点击任一按钮,它的 onClick 将首先运行,然后是父节点

的 onClick—— 所以会出现两条消息。
学新通
学新通 学新通如果你点击灰色区域本身,只有父
的 onClick 会运行。

1.1 停止传播

为阻止传播,可以在onClick中加一行引用事件参数e并调用e.stopPropagation()方法,此时当用户点击<button>触发器该条语句,停止事件向外扩散,父节点<div>的onClick将不再触发。

1.2 阻止默认事件

e.preventDefault() 阻止默认行为
<form>:当内部按钮点击后,将默认重载整个页面

export default function Signup() {
  return (
    <form onSubmit={e => {
      e.preventDefault();    //点击按钮后将不再重载页面
      alert('Submitting!');
    }}>
      <input />
      <button>Send</button>
    </form>
  );
}

2. [Hook] useState 状态

形式:const [index, setIndex] = useState(默认值)

“[]”从useState解构出来两部分,

  1. 用于保留渲染之间数据的状态变量index
  2. 一个状态设置函数,setIndex用于更新变量触发 React 再次渲染组件

只能使用在组件,不能在条件、循环或其他嵌套函数中调用 Hooks,hook调用原理:
React报错#310复盘小结 hooks使用的场景 调用原理

只有 Hook 的调用顺序在多次渲染之间保持一致,React 才能正确地将内部 state 和对应的 Hook 进行关联。

useState内部:

React 为每个组件保存一组状态对。 它还维护当前对索引,该索引在渲染前设置为 0。 每次调用 useState 时,React 都会为您提供下一个状态对并递增索引。

let componentHooks = [];
let currentHookIndex = 0;
// How useState works inside React (simplified).
function useState(initialState) {
  let pair = componentHooks[currentHookIndex];
  if (pair) {
    // This is not the first render,
    // so the state pair already exists.
    // Return it and prepare for next Hook call.
    currentHookIndex  ;
    return pair;
  }

  // This is the first time we're rendering,
  // so create a state pair and store it.
  pair = [initialState, setState];

  function setState(nextState) {
    // When the user requests a state change,
    // put the new value into the pair.
    pair[0] = nextState;
    updateDOM();
  }

  // Store the pair for future renders
  // and prepare for the next Hook call.
  componentHooks[currentHookIndex] = pair;
  currentHookIndex  ;
  return pair;
}
学新通

3. 渲染和提交

举个例子:

组件是厨房里的厨师,用食材烹制美味佳肴。React 是一个服务员,负责接收客户的订单并为他们带来菜肴。这个请求和提供 UI 的过程分为三个步骤:

  1. 触发渲染(将客人的订单送到厨房)
  2. 渲染组件(在厨房准备订单)
  3. 提交给 DOM(将制作好的菜肴放在客户的桌上)
    学新通

3.1 触发渲染

组件渲染有两个原因:

  1. 初始渲染
    root.render(<App />);

  2. 组件(或其祖先之一)的state已更新

3.2 React渲染组件

export default function Gallery() {
  return (
    <section>
      <h1>Inspiring Sculptures</h1>
      <Image />
      <Image />
    </section>
  );
}
function Image() {
  return (
    <img src="xxx" alt="xxx" />
  );
}
  • 在初始渲染时,React 将调用根组件。
    <section><h1> 和两个<img>标签创建DOM节点

  • 对于后续的渲染,React 将调用状态更新触发渲染的函数组件
    React 将计算它们的哪些属性(如果有)自上次渲染以来发生了变化。 在下一步,即提交阶段之前,它不会对这些信息做任何事情。

3.3 提交对 DOM 的更改

  • 初始渲染时,React 将使用appendChild() DOM API 将它创建的所有 DOM 节点放在屏幕上。
  • 对于重新渲染,React 将应用最少的必要操作(在渲染时计算!)以使 DOM 匹配最新的渲染输出。

如果渲染之间存在差异,React 只会更改 DOM 节点。

举例:
Clock组件会随着父节点传入不同的props 参数 time 而重新渲染,但在input中输入‘1’,重新渲染时‘1’没有消失。

export default function Clock({ time }) {
  return (
    <>
      <h1>{time}</h1>
      <input />
    </>
  );
}

学新通学新通

这是因为随着time的改变, React 只更新了<h1>的内容,而没有触及<input>

3.4 浏览器绘制

渲染完成并且 React 更新 DOM 后,浏览器将重新绘制屏幕

4. 渲染快照

当 React 重新渲染一个组件时:

  1. React 再次调用你的函数。
  2. 您的函数返回一个新的 JSX 快照(使用该渲染中的state计算的,在快照中保持状态值“固定”)
  3. React 然后更新屏幕以匹配您返回的快照。

学新通
setState 只会为下一次渲染更改它

export default function Counter() {
  const [number, setNumber] = useState(0);
  return (
    <>
      <h1>{number}</h1>
      <button onClick={() => {
        setNumber(number   1);
        setNumber(number   1);
      }}> 2</button>
    </>
  )
}

点击第一次后:
学新通
点击第二次后:
学新通
发现两次点击都只加了1

在第一次渲染期间,number是0,调用onClick:
第一个setNumber(number 1)等价于 setNumber(0 1)
第二个setNumber(number 1)等价于 setNumber(0 1)
React 准备在下一次渲染时更改number为1,也就是说设置状态为1了两次
学新通

在处理状态更新之前,React 会等到事件处理程序中的所有代码都已运行。这使您可以更新多个状态变量——甚至来自多个组件——而不会触发太多重新渲染

q: 在下一次渲染之前需要多次更新相同的state?


答: 可以传递一个函数,该函数根据前一个状态计算下一个状态队列
例如将上述例子替换为setNumber(n => n 1);

n => n 1更新函数(必须是纯函数并且只返回结果)

当您将它传递给状态设置器时:

  1. 在事件处理程序中的所有其他代码运行之后,React 将此函数排队等待处理。
  2. 在下一次渲染期间,React 遍历队列并为您提供最终的更新状态。
队列更新 n returns
n => n 1 0 0 1=1
n => n 1 1 1 1=2

状态队列例子

实现状态队列:https://codesandbox.io/s/0xym3z?file=/processQueue.js&utm_medium=sandpack

<button onClick={() => {
  setNumber(number   5);
  setNumber(n => n   1);
  setNumber(42);
}}>
队列更新 n returns
“replace with 5” 0(unused) 5
n => n 1 5 5 1=6
“replace with 42” 6(unused) 42

在下一次渲染期间,React 遍历状态队列:

  1. setNumber(number 5): number是0,所以setNumber(0 5)。React 将“替换为5”添加到它的队列中。
  2. setNumber(n => n 1): n => n 1是一个更新函数。React 将该函数添加到它的队列中。
  3. setNumber(42): React 将“替换为42”添加到它的队列中。

5. 更新state中的对象

用 Immer 编写简洁的更新对象state逻辑:Immer编写简洁的更新state逻辑

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgagffi
系列文章
更多 icon
同类精品
更多 icon
继续加载