React中是否存在Solid.js的mergeProps与splitProps等价方法?
React中替代Solid.js的
mergeProps与splitProps的方案 一、替代mergeProps的方案
Solid.js的mergeProps会智能合并props对象:事件处理器按顺序执行、className/style自动合并而非覆盖。在React生态中,**React Aria的mergeProps**完全匹配这个功能,它专门针对React组件的props合并做了优化:
- 安装依赖(若未安装):
npm install react-aria
- 导入并使用,用法和Solid.js版本完全一致:
import { mergeProps } from 'react-aria'; const propsWithDefault = mergeProps({ as: component }, props);
如果不想依赖第三方库,也可以自定义简易版mergeProps,覆盖核心合并逻辑:
function mergeProps(...sources) { const result = {}; for (const source of sources) { if (!source) continue; for (const key in source) { if (key === 'className') { result.className = [result.className, source.className].filter(Boolean).join(' '); } else if (key === 'style') { result.style = { ...result.style, ...source.style }; } else if (typeof source[key] === 'function' && typeof result[key] === 'function') { // 合并事件处理器,按顺序执行 const prevHandler = result[key]; result[key] = (...args) => { prevHandler(...args); source[key](...args); }; } else { result[key] = source[key]; } } } return result; }
二、自定义实现splitProps
Solid.js的splitProps可以将单个props对象拆分为多个子集,指定键的子集单独提取,剩余键归最后一个返回值。React没有内置该功能,可自行实现:
function splitProps(props, ...keysArrays) { const result = []; const remaining = { ...props }; for (const keys of keysArrays) { const subset = {}; for (const key of keys) { if (remaining.hasOwnProperty(key)) { subset[key] = remaining[key]; delete remaining[key]; } } result.push(subset); } result.push(remaining); return result; }
用法和Solid.js版本完全一致:
const [local, styleProps, others] = splitProps( propsWithDefault, ["as", "class", "className", "__baseStyle"], usedStylePropNames );
三、迁移代码的修改示例
替换原Solid.js的mergeProps/splitProps导入,修改后的核心代码片段如下:
import React, { FC, ReactNode, useMemo } from "react"; import { mergeProps } from "react-aria"; import { createStyledSystemClass, getUsedStylePropNames } from "../styled-system/system"; import { isFunction } from "../utils/assertion"; import { classNames, createClassSelector } from "../utils/css"; // 自定义splitProps函数 function splitProps(props, ...keysArrays) { const result = []; const remaining = { ...props }; for (const keys of keysArrays) { const subset = {}; for (const key of keys) { if (remaining.hasOwnProperty(key)) { subset[key] = remaining[key]; delete remaining[key]; } } result.push(subset); } result.push(remaining); return result; } const styled: HopeFactory = <T extends ElementType>( component: T, styleOptions?: HopeFactoryStyleOptions<T> ) => { const hopeComponent: HopeComponent<T> = props => { const usedStylePropNames = getUsedStylePropNames(props); const propsWithDefault = mergeProps({ as: component }, props); const [local, styleProps, others] = splitProps( propsWithDefault as HTMLHopeProps<any>, ["as", "class", "className", "__baseStyle"], usedStylePropNames ); const __baseStyles = useMemo(() => { const factoryBaseStyle = isFunction(styleOptions?.baseStyle) ? styleOptions?.baseStyle(props as any) : styleOptions?.baseStyle; return [factoryBaseStyle, local.__baseStyle]; },[local.__baseStyle, props]); const classes = () => classNames( styleOptions?.baseClass, local.class, local.className, createStyledSystemClass(styleProps, __baseStyles) ); // 修复Dynamic组件的逻辑问题 const Dynamic: FC<{ as: ElementType, children: ReactNode, ...restProps }> = ({ as: Component, children, ...restProps }) => { return React.createElement(Component || 'div', restProps, children); }; return <Dynamic as={local.as} className={classes()} {...others}>{props.children}</Dynamic>; }; hopeComponent.toString = () => styleOptions?.baseClass ? createClassSelector(styleOptions.baseClass) : ""; return hopeComponent; }; // 后续factory和hope导出逻辑保持不变
内容的提问来源于stack exchange,提问作者Shahriaz Kobir
相关产品推荐
相关产品推荐

