【问题标题】:Universal solution for data attributes in ReactReact 中数据属性的通用解决方案
【发布时间】:2021-01-11 02:08:58
【问题描述】:
我的项目中有一些重复的代码,如下所示:
function MyComp({prop1, prop2, ...restProps}) {
// ...
const dataAttributes = Object.keys(restProps).reduce((acc, key) => {
if (key.startsWith('data-')) {
acc[key] = restProps[key];
}
return acc;
}, {});
return (
<div {...dataAttributes}>
{/* ... */}
</div>
);
}
我正在考虑这种行为的自动化(如果它是一个 html 元素,则将以 data- 开头的 props 传递给组件的根元素)。
有什么想法吗?
【问题讨论】:
标签:
javascript
reactjs
custom-data-attribute
【解决方案1】:
也许你可以为你使用的 html 标签创建一个自定义组件,比如 RichDiv、RichSpan... 它会是这样的:
const getDataAttributes = (inputProps = {}) => Object.keys(inputProps).reduce((acc, key) => {
if (key.startsWith('data-')) {
acc[key] = inputProps[key];
}
return acc;
}, {});
function RichDiv({children, className, ...restProps}) {
const dataAttributes = getDataAttributes(restProps);
return (
<div {...dataAttributes} className={className}>
{children}
</div>
);
}
function RichSpan({children, className, ...restProps}) {
const dataAttributes = getDataAttributes(restProps);
return (
<span {...dataAttributes} className={className}>
{children}
</span>
);
}
您可以将任何其他列入白名单的道具添加到自定义组件中,就像我对 className 所做的那样,甚至可以改进您制作的道具过滤器功能,使其返回数据属性和其他 HTML 通用属性。然后,您只需导入并使用 RichDiv 而不是原版 div 等等。
【解决方案2】:
第一步但不是很复杂的步骤可能是将归约部分提取为单独的效用函数,如下所示:
export function extractDataAttributes(props) {
return Object.keys(props).reduce((acc, key) => {
if (key.startsWith("data-")) {
acc[key] = props[key];
}
return acc;
}, {});
}
那么你可以通过以下更短的方式使用它:
function MyComp({prop1, prop2, ...restProps}) {
// ...
return (
<div {...extractDataAttributes(restProps)}>
{/* ... */}
</div>
);
}
通过这样做,您还将明确标记生成的标记具有data-attributes。另一方面,不会有不必要的细节。
如果您在某些时候发现此解决方案不够充分,那么使用 HOC 查看其子级并更新它们可能是个好主意。但是,这种方法可能会降低代码的明确性。
【解决方案3】:
您可以创建一个 HOC 函数,在其中您可以将剩余的道具传递给组件:
const withDataAttribute = (Component) => (props) => {
let passThroughProps = { ...props }
const dataAttributes = Object.keys(passThroughProps).reduce((acc, key) => {
if (key.startsWith('data-')) {
acc[key] = passThroughProps[key];
const { [key]: any, ...rest } = passThroughProps
passThroughProps = rest
}
return acc;
}, {});
return (
<div {...dataAttributes}>
<Component {...passThroughProps} />
</div>
);
}