Как присвоить компонентам react динамические идентификаторы, когда React запускает код дважды?

#javascript #reactjs

Вопрос:

Это известное поведение реакции, когда код выполняется дважды.

Тем не менее, я создаю конструктор форм, в котором мне нужно иметь возможность присваивать каждой вводимой форме динамический идентификатор и использовать этот идентификатор для множества других целей позже. Вот простой код ввода:

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

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

Но поскольку Math.random() это побочный эффект, он вызывается дважды, и я не могу создавать динамические идентификаторы для полей моей формы.

Причину, по которой я это использую document.querySelector , можно прочитать здесь.

Мой вопрос в том, как я могу создавать согласованные динамические идентификаторы для своих входных данных?

Комментарии:

1. используйте текущее время или uuid

2. @cybercoder, ты имеешь в виду что-то вроде const [id, setId] = useState(new Date()) ? Это привело бы к той же проблеме.

3. Почему бы не использовать ref вместо document.querySelector «а»? id В таком случае вам это не понадобится.

4. Math.random() является только «побочным эффектом», если он не возвращает то же значение при втором вызове (очень вероятно). Но даже если бы он вернул другое значение, я не вижу, как это могло бы быть проблемой в ограниченной области вашего фрагмента кода. Ваш эмиттер событий не должен находиться в теле функционального компонента. Именно в этом заключается ваша проблема, поскольку тело компонента функции также дважды вызывается для обнаружения непреднамеренных побочных эффектов.

5. @DrewReese, государственное управление React-это почти ад. Очень простые вещи, которыми можно управлять в простом приложении между компонентами, быстро становятся настолько сложными и замусоренными шаблоном, что мы много раз терпели неудачи Redux при использовании React Context и. Поэтому мы решили смешать React с легкими вещами старой школы, которые мы знали как команда. EventEmitter является одним из них. Это динамический конструктор форм, и все настолько динамично, что React не помогает.

Ответ №1:

Похоже, вы думаете, что useState(Math.random()); это побочный эффект, вызывающий проблему, но дважды вызываются только переданные функции useState .

Я думаю, что проблема, с которой вы столкнулись, заключается в том, что eventEmitter.on вызов является непреднамеренным побочным эффектом, поскольку тело компонента функции также вызывается дважды.

Строгий режим не может автоматически определять побочные эффекты для вас, но он может помочь вам определить их, сделав их немного более детерминированными. Это делается путем преднамеренного двойного вызова следующих функций:

  • Компонент класса constructor , render , и shouldComponentUpdate методы
  • Статический getDerivedStateFromProps метод компонента класса
  • Тела функциональных компонентов
  • Функции обновления состояния (первый аргумент setState )
  • Функции, переданные useState , useMemo , или useReducer

Чтобы исправить это, я считаю, что вы должны поместить 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]);

  ...
}
 

Комментарии:

1. Спасибо, что уделили мне время. Если Math.random() это не проблема, то почему я получаю два значения? Вы можете увидеть это в действии здесь

2. Конечно, это потому <React.StrictMode> , что это не будет беспокоить в производстве. Но мне нужно, чтобы я мог получить то же id самое и в режиме разработки.

3. @HosseinFallah Верно, я просто тестировал все это в codesandbox в качестве проверки на вменяемость. Интересно, что в React v17 я не вижу побочных эффектов, но в React v16 я вижу. В связанной песочнице я показываю побочный эффект и не побочный эффект в useEffect крючке, чтобы вы могли увидеть разницу.

4. Я видел песочницу. Но я не понимаю, как это мне помогает. Я использую React 17.0.2 , и я использую StrictMode , и я все еще получаю два идентификатора.

5. Дело в том, что когда внутри useEffect я хочу повторно использовать элемент document.querySelector , мой код обращается ко второму id . В то время как тот id={id} дал моей стихии первое id . Вы поняли, в чем проблема?