从外部库触发时反应状态不反应

React state not reactive when triggered from outside library

这里是 React 初学者。

我的代码

import Head from 'next/head';
import styles from '../styles/Home.module.css';
import { useState, useEffect } from 'react';
import Mousetrap from 'mousetrap';

export default function Home() {
  const [count, setCount] = useState(0);

  const triggerSomething = () => {
    console.log(count);
  };

  useEffect(() => {
    Mousetrap.bind(['ctrl+s', 'command+s'], e => {
      e.preventDefault();
      triggerSomething();
    });

    return () => {
      Mousetrap.unbind(['ctrl+s', 'command+s']);
    };
  }, []);

  return (
    <div className={styles.container}>
      <main className={styles.main}>
        <h1 className={styles.title}>count: {count}</h1>

        <p className={styles.description}>
          <button onClick={() => setCount(count + 1)}>increment</button>
          <br />
          <br />
          <button onClick={triggerSomething}>triggerSomething</button>
        </p>
      </main>
    </div>
  );
}

我在尝试从 Mousetrap 触发事件时遇到问题。 count 变量在从捕鼠器触发时没有反应,但在使用 onClick.

的按钮触发时有反应

要复制此错误,您需要:

  1. 单击一次增量按钮
  2. 单击 triggerSomething 按钮。控制台应该打印出 1count 的当前状态)
  3. 按 command+s 或 ctrl+s 触发相同的方法。控制台打印出0(组件加载时count的状态)。 那应该打印 1(当前状态)。

我做错了什么?我应该在这里使用什么模式?

更新: Stackblitz here

当你改变状态时,组件被重新渲染,即函数被再次执行,但是 useState hook returns 这次更新了计数器。要在 MouseTrap 中使用这个更新后的值,您必须创建一个新的处理程序(并删除旧的)。为此,只需删除 useEffect 调用的依赖项数组。然后它将使用新创建的 triggerSomething 函数。

import Head from 'next/head';
import styles from '../styles/Home.module.css';
import { useState, useEffect } from 'react';
import Mousetrap from 'mousetrap';

export default function Home() {
  const [count, setCount] = useState(0);

  const triggerSomething = () => {
    console.log(count);
  };

  useEffect(() => {
    Mousetrap.bind(['ctrl+s', 'command+s'], e => {
      e.preventDefault();
      triggerSomething();
    });

    return () => {
      Mousetrap.unbind(['ctrl+s', 'command+s']);
    };
  }); // Notice that I removed the dependency array

  return (
    <div className={styles.container}>
      <main className={styles.main}>
        <h1 className={styles.title}>count: {count}</h1>

        <p className={styles.description}>
          <button onClick={() => setCount(count + 1)}>increment</button>
          <br />
          <br />
          <button onClick={triggerSomething}>triggerSomething</button>
        </p>
      </main>
    </div>
  );
}

triggerSomething 方法中,您可以使用 setCount(count => count + 1),这应该有效。

您遇到的问题是当您不将 triggerSomething 作为 useEffect 中的 dep 时,计数将与初始状态相同,即 0。但是当传递一个函数依赖于 setCount 的先前值,您将避免此问题。