Как добавить обработчики событий в узел JSX по имени события?

#javascript #reactjs #event-handling #jsx

Вопрос:

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

 const Component(eventName, handler) => {
   return <div>{...}</div>
}
 

Моя первоначальная идея состояла в том, чтобы создать объект реквизита и распространить его на компонент:

 const Component(eventName, handler) => {

   const props = { ['on' eventName]: handler };
   
   return <div {...props}>
       {...}
   </div>
}
 

Проблема в том, что название события пишется строчными буквами, например click , dragend , и т. Д

И вместо этого ожидайте синтаксиса верблюжьего регистра.

Поэтому, если я получу строку «щелчок» в качестве реквизита, она должна превратиться в onClick ключ для props объекта. Это не так просто, как написать событие с заглавной буквы и добавить к нему «вкл», так как некоторые события содержат несколько слов. Например, dragend нужно превратиться в onDragEnd то, чтобы реагировать, чтобы быть счастливым.

У кого-нибудь есть предложения, как я могу это сделать, не сохраняя огромный список имен событий — > свойства jsx, отображенные в этом компоненте?

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

1. вы можете правильно передать имя события, поэтому вместо перетаскивания введите DragEnd, затем вы можете просто добавить к нему «вкл».

2. вы также можете обойтись меньшим списком, например: [«мышь», «перетаскивание»,…], а затем проверить, начинается ли строка с одного из них. Это будет работать только для 2-х словесных событий, но этого может быть достаточно для вашего варианта использования.

Ответ №1:

Ожидают ли функции обработчика событий, что при их вызове им будет передан объект события браузера или объект синтетического события react?

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

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

 import React, { useEffect, useRef } from "react";
import isDeepEqual from "fast-deep-equal/react";

const testEvents = {
  click: () => console.log("click event handler fired!"),
  mouseover: () => console.log("mouseover event handler fired!"),
  mouseleave: () => console.log("mouseleave event handler fired!")
};

const TestComponent = ({ events }) => {
  const ref = useRef(null);
  const memoizedEvents = useMemoizedEvents(events);
  useEffect(() => {
    const currentRef = ref.current;
    Object.entries(memoizedEvents).forEach(([name, handler]) =>
      currentRef.addEventListener(name, handler)
    );
    // This function cleans up old event handlers.
    // It will run whenever memoziedEvents changes before the new handlers are registered.
    return () =>
      Object.entries(memoizedEvents).forEach(([name, handler]) =>
        currentRef.removeEventListener(name, handler)
      );
  }, [memoizedEvents]);
  return (
    <div ref={ref}>
      DOM Element with Event Handlers
    </div>
  );
};

/**
 * This hook makes sure that the "events" object only changes identity if any of the things within it have changed.
 * This way, the effect that registers/unregisters the click handlers won't run unnecessarily.
 */
function useMemoizedEvents(events) {
  const eventsRef = useRef();
  if (!isDeepEqual(eventsRef.current, events)) {
    eventsRef.current = events;
  }
  return eventsRef.current;
}

const App = () => <TestComponent events={testEvents} />;

 

Смотрите этот код и поле