我正在使用React,并且有一个组件只需要渲染子元素并根据条件为它们添加一个类。 最佳实现方法是什么?
我正在使用React,并且有一个组件只需要渲染子元素并根据条件为它们添加一个类。 最佳实现方法是什么?
一周前我想通了,这就是我想要的:
export default class ContainerComponent extends React.Component {
constructor(props) {
super(props);
this.modifyChildren = this.modifyChildren.bind(this);
}
modifyChildren(child) {
const className = classNames(
child.props.className,
{...otherClassses}
);
const props = {
className
};
return React.cloneElement(child, props);
}
render() {
return (<div>
{React.Children.map(this.props.children, child => this.modifyChildren(child))}
</div>);
}
}
出于简化考虑:
const StyleInjector = ({ children }) => {
const StyledChildren = () =>
React.Children.map(children, child =>
React.cloneElement(child, {
className: `${child.props.className} ${PUT_YOUR_CLASS_HERE}`
})
);
return <StyledChildren />;
};
{children, className}
替换StyleInjector的args,并将PUT_YOUR_CLASS_HERE
替换为className
。
使用示例:<StyleInjector className="classsss"><li>dd1</li><li>dd2</li></StyleInjector>
。 - certainlyakey几周前,我需要在React中实现一个轮播的场景,没有什么华丽的效果,只是简单地切换活动类。我采取了这种方法,它非常好用,但请注意这是否是一个好方法。
{
this.props.children.map((slide, index) => {
return React.cloneElement(slide, {
key: index,
className: (this.state.currentActiveIndex === index) ?'active' : ''
});
})
}
cloneElement
是最好的方法。你实际上正在使用API的用途。 - denyzprahy您可以将一个prop传递给子组件,然后它可以选择应用哪个类(或者只传递类名,但这更语义化):
<Parent contentVisible={true}>
<Child />
</Parent>
const classes = [];
if (props.contentVisible)
classes.push('visible');
<div className={classes.join(' ')} />
import * as React from 'react';
import type { ReactNode, ReactElement, ReactPortal, PromiseLikeOfReactNode, ReactFragment } from 'react';
type StylizeChildrenProps = {
children?: ReactNode
className: React.HTMLAttributes<any>['className']
}
export function StylizeChildren({ children, className = '' }: StylizeChildrenProps) {
if (children == null) return null;
className = className.trim();
if (!className) return <>{children}</>
return <>
{React.Children.map(children, child => addClassToNode(child, className))}
</>
}
// Separate out into its own function because Promise-like nodes require this to be recursive
export function addClassToNode(node: ReactNode, className: string): ReactNode {
if (node == null) {
node satisfies null | undefined
return node
}
if (typeof node !== 'object') {
node satisfies string | number | boolean
// wrap in a span, somewhat arbitrary decision
return <span className={className}>{node}</span>
}
if ('props' in node) {
node satisfies ReactElement | ReactPortal
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
const existing: unknown = node?.props?.className;
if (existing && typeof existing === 'string') {
className = `${existing} ${className}`
}
return React.cloneElement(node, { className })
}
if ('then' in node) {
node satisfies PromiseLikeOfReactNode
return node.then(n => addClassToNode(n, className))
}
node satisfies ReactFragment
// wrap in div, somewhat arbitrary decision
return <div className={className}>{node}</div>
}
修改此代码以在遇到非对象类型或React片段时执行其他操作将变得简单。例如,React片段是可迭代的,因此您可以通过迭代其所有子项并为其设置类来替换它。
存在satisfies
语句是因为我认为它们使情况更清晰,并且如果底层类型或React API发生更改,则会揭示一些令人讨厌的错误。如果您运行的Typescript版本低于4.9,请删除它们,一切都应该正常工作。
在你的组件的渲染方法内:
var childClasses = [],
childClassNames;
if (condition) {
childClasses.push('my-class-name');
}
childClassNames = childClasses.join(' ');
return (<div className={childClassNames}>
.... (your component here)
</div> );