【问题标题】:How to add an event handlers to JSX node by event name?如何通过事件名称将事件处理程序添加到 JSX 节点?
【发布时间】:2021-10-08 18:46:35
【问题描述】:

我有一个常见的情况,一个 React 组件接收一个事件名称和一个处理函数作为 props,我必须在这个组件返回的元素中为该事件附加这个函数一个事件处理程序:

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

我最初的想法是创建一个 props 对象并在组件上传播:

const Component(eventName, handler) => {

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

问题是事件名是小写的,比如clickdragend

而 React 期望使用驼峰式语法。

所以如果我收到“点击”字符串作为道具,它必须变成props 对象上的onClick 键。这不像将事件大写并在其前面加上“on”那么简单,因为某些事件有多个单词。例如,dragend 需要变成 onDragEnd 才能让 React 满意。

有没有人建议我如何在不维护大量事件名称的情况下完成此操作 -> jsx 属性映射在此组件中?

【问题讨论】:

  • 你可以正确地传递事件名称,所以不要使用dragend,而是传递DragEnd,然后你可以在它前面加上“on”。
  • 您也许还可以使用较小的列表,例如: ['mouse', 'drag', ...] 然后检查字符串是否以其中之一开头。这仅适用于 2 个单词的事件,但对于您的用例来说可能已经足够了。

标签: javascript reactjs event-handling jsx


【解决方案1】:

事件处理函数是否期望当它们被调用时,它们将被传递给浏览器事件对象,或反应合成事件对象?

如果他们期待浏览器事件(这似乎是因为他们使用了浏览器事件命名约定),那么注册所有具有效果的事件可能是有意义的 - 见下文。

请注意,我已经完成了记忆事件道具对象的工作。这对于功能来说并不是绝对必要的,但如果此事件对象在您的组件的父级中频繁更改身份,它将有助于提高性能:

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} />;

this CodeSandbox

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-30
    • 1970-01-01
    • 2021-02-26
    • 2018-08-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多