我有一个常见的情况,一个React组件接收一个事件名称和一个处理程序函数作为props,我必须在这个组件返回的元素中为该事件附加这个函数和一个事件处理程序:
const Component(eventName, handler) => {
return <div>{...}</div>
}
我最初的想法是创建一个props对象并在组件上展开:
const Component(eventName, handler) => {
const props = { ['on'+eventName]: handler };
return <div {...props}>
{...}
</div>
}
问题是事件名称是小写的,如click
,dragend
等
React期望使用驼峰大小写语法。
所以如果我收到'click'字符串作为道具,它必须在props
对象上变成onClick
键。这并不像将事件大写并在前面加上"on"那么简单,因为有些事件有多个单词。例如,dragend
需要变成onDragEnd
, React才会高兴。
有没有人有建议,我如何才能在不维护一个巨大的事件名称列表的情况下完成这一点->在此组件中映射的JSX属性?
事件处理程序函数是否期望当它们被调用时,它们将被传递一个浏览器事件对象,或一个react合成事件对象?
如果他们期望浏览器事件(这似乎是可能的,因为他们正在使用浏览器事件命名约定),那么将所有事件注册为effect可能是有意义的-见下文。
注意,我已经完成了记忆事件道具对象的工作。这对于功能来说并不是严格必需的,但是如果这个事件对象在组件的父组件中频繁地更改标识,它将有助于提高性能:
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} />;
查看此CodeSandbox