首页 > 解决方案 > 当 React 运行代码两次时,如何为反应组件提供动态 ID?

问题描述

代码运行两次是一种已知的 React 行为

但是,我正在创建一个表单构建器,在其中我需要能够为每个表单输入提供一个动态 Id,并在以后将该 Id 用于许多其他目的。这是一个简单的输入代码:

const Text = ({placeholder}) => {
    const [id, setId] = useState(Math.random());

    eventEmitter.on('global-event', () => {
       var field = document.querySelector(`#${id}`); // here, id is changed
    });
}

但由于Math.random()是副作用,它被调用了两次,我无法为我的表单字段创建动态 ID。

我使用的原因document.querySelector可以在这里阅读。

我的问题是,如何为我的输入创建一致的动态 ID?

标签: javascriptreactjs

解决方案


您似乎认为这useState(Math.random());是导致您问题的副作用,但只有传递给的函数才会useState被双重调用。

我认为您遇到的问题是eventEmitter.on调用是无意的副作用,因为函数组件主体也被双重调用。

严格模式不能自动为您检测副作用,但可以通过使它们更具确定性来帮助您发现它们。这是通过有意双重调用以下函数来完成的:

  • 类组件constructor,rendershouldComponentUpdate方法
  • 类组件静态getDerivedStateFromProps方法
  • 函数组件体<--this
  • 状态更新函数( 的第一个参数setState
  • 传递给useStateuseMemouseReducer< 的函数——不是 this

为了解决这个问题,我认为您应该将eventEmitter.on逻辑放入useEffect依赖于id状态的钩子中。您还应该使用id可以保证更多唯一性的值。不要忘记从效果中返回一个清理函数以删除任何活动的事件“侦听器”,无论是在id更新时,还是在组件卸载时。这是为了帮助清除任何资源泄漏(内存、套接字等)。

例子:

import { v4 as uuidV4 } from 'uuid';

const Text = ({placeholder}) => {
  const [id, setId] = useState(uuidV4());

  useEffect(() => {
    const handler = () => {
      let field = document.querySelector(`#${id}`);
    };

    eventEmitter.on('global-event', handler);

    return () => {
      eventEmitter.removeListener('global-event', handler);
    };
  }, [id]);

  ...
}

推荐阅读