React 事件处理程序的陷阱与克服方法

首先

你好,我是Kazuya(@bearone236)!这次我们将重点介绍React的事件处理程序,并详细解释其功能和事件处理程序的行为。

React是一个强大的框架,事件处理也是其中的一部分。然而,如果使用不正确,可能会导致奇怪的行为。

在这篇文章中,我将解释我在使用React事件处理程序时遇到的问题以及解决方法。我们还将一起探讨React和JavaScript的协作问题?。

这次我们不会详细解释React,但是如果有时间的话,我想在另一篇博客中总结React学习的必备知识,如虚拟DOM和渲染等。

事件处理程序是什么?

一般而言,事件处理程序指的是当事件触发时执行的代码块或函数(通常是用户定义的 JavaScript 函数)。

在React中,可以在JSX代码中编写事件处理程序,以响应用户交互,例如点击、表单输入、窗口处理和鼠标处理等。


因此,事件处理程序有时也被称为 “事件触发器”。

在这次活动处理函数的传递中,我们观察到意外的行为。我们将进行更深入的研究。这些都是开发所需的知识,请务必在这里学习。

如果您对此次的操作和问题解决方案有兴趣,可以在 React 官方网站中找到具体的详情,请务必阅读。

5个意外行为

【意外な動作 1】使用useState钩子的事件处理程序

下面的代码是通过点击按钮触发 onClick 函数,并使用 useState 来逐渐增加 count 变量的预期描述。

<button onClick={setCount(count + 1)}>Click</button>

当声明此事时,将出现“太多次重渲染。React限制渲染次数以防止无限循环”的错误信息。(无限循环)

据说,这是由于事件处理程序本身直接造成的,但是useState和渲染也与无限循环问题有关。

这里不具体解释了,但简单来说,React 有一个条件用来判断何时进行渲染,就是当状态更新时。useState函数用于计数,每次调用useCount函数时都会更新状态,从而导致重新渲染。

【非预期的行为 2】 使用控制台的事件处理程序

这段代码是根据猜测,每次点击按钮时都会输出 console.log(‘test’)。

<button onClick={console.log("test")}>Click</button>
【実行結果】

(何度クリックしても何も表示されない)

在具有 onClick 属性的代码中,当组件渲染时,console.log(“test”) 将被执行。

这是由于JavaScript执行console.log(“test”)并将其返回值(在这种情况下是undefined)设置为onClick事件处理程序而导致的行为。

→ 因此,在实际点击按钮时不会发生任何事情。

【不期望的行为 3】当向函数传递参数时的事件处理程序。

export default function App() {
  const e = 0;
  function handleChange(e) {
    console.log(`test: ${e}`);
  }
  return (
    <div>
      <button onClick={handleChange(e)}>Count</button>
    </div>
  );
}
【実行結果】

(何度クリックしても何も表示されない)

使用函数参数执行了与示例2相同的操作,但观察到了上述相似的输出结果。

【不符合预期的行为 4-1】使用无参数函数的事件处理程序

export default function App() {
  function handleChange() {
    console.log("test");
  }
  return (
    <div>
      <button onClick={handleChange}>Count</button>
    </div>
  );
}

通过如此形式的定义函数并在 JSX 描述之外触发,可以看到正常运行的结果。

可以通过将挙動1中的useState钩子代码更改为相同的格式来实现正常工作。

【意外な挙動 4-2】 使用带参数但无返回值的函数作为事件处理器。

export default function App() {
  function handleChange() {
    console.log("test");
  }
  return (
    <div>
      <button onClick={handleChange()}>Count</button>
    </div>
  );
}
【実行結果】

(何度クリックしても何も表示されない)

然而,当在函数中使用参数时,可能会出现意料之外的行为。

→ 函数传参是否有问题…?
→ 是否存在有无参数的区别…?

解决! !)

在 React 公式文档的“陷阱”部分中,包含了所有疑问的解答。

【当需要使用函数作为事件处理程序时】

関数を渡す (正しい ⭕️)関数を呼び出す(間違い ❌ )コード<button onClick={handleClick}><button onClick={handleClick()}>処理handleClick 関数が onClick イベントハンドラとして渡されているhandleClick()の末尾に空の()が存在している詳細React にこの関数を覚えてもらい、ユーザーがアクションを行った時にのみコールするように指示しているアクションを必要とせず、レンダーの際にすぐに実行されてしまう

→ JSX 中的代码将立即执行

※ “事件处理程序中传递的函数应该是’传递’而不是’调用'”

在定义函数时,无论是函数声明还是箭头函数,都需要使用参数来执行“传递函数”的操作!


当需要在内联代码中直接使用事件处理程序时。

接下来,我们将说明如何在JSX中编写内联代码。

関数を渡す (正しい ⭕️)関数を呼び出す(間違い ❌)コード<button onClick={() ⇒ console.log(’…’)}><button onClick={console.log(’…’)}>処理アロー関数(無名関数)を用いてインラインコードラップしているイベントハンドラonClickに直接インラインコードを記載している詳細レンダーごとに中のコードが実行されているのではなく、後で呼び出されるべき関数を作成したことになるクリックした時ではなく、コンポーネントがレンダーされるたびに実行されます

当使用 useState 时,state 将不断更新,达到了”无限循环”的完成。

总结

在JSX的外部而不是内联定义函数时,编写不需要参数的”传递函数的操作”。

2. 在 JSX 中想要内嵌的时候,需要用箭头函数来编写处理。

只要你需要在函数中使用参数,就使用箭头函数进行定义!(以下是代码示例)

【使用TypeScript撰写的参考代码】

export const Board: React.FC<BoardProps> = ({ squares, onClick }) => {
  const callSquare = (i: number) => {
    return <Square value={squares[i]} onClick={() => onClick(i)} />;
  };

  return (
    <div>
      <div className="board-row">
        {callSquare(0)}
        {callSquare(1)}
        {callSquare(2)}
      </div>
      <div className="board-row">
        {callSquare(3)}
        {callSquare(4)}
        {callSquare(5)}
      </div>
      <div className="board-row">
        {callSquare(6)}
        {callSquare(7)}
        {callSquare(8)}
      </div>
    </div>
  );
};

文献引用