reactjs React -将类添加到子组件

hyrbngr7  于 2023-05-28  发布在  React
关注(0)|答案(6)|浏览(201)

我正在使用react,我有一个组件,它只需要呈现孩子并根据条件为他们添加一个类。做这件事的最好方法是什么?

sbtkgmzw

sbtkgmzw1#

我一周前就想明白了,这就是我想要的:

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>);
    }
}
50few1ms

50few1ms2#

为了简单起见:

const StyleInjector = ({ children }) => {
   const StyledChildren = () =>
    React.Children.map(children, child =>
      React.cloneElement(child, {
        className: `${child.props.className} ${PUT_YOUR_CLASS_HERE}`
      })
    );

  return <StyledChildren />;
};
zf9nrax1

zf9nrax13#

几周前,我有一个狂欢的场景要在react中实现,没有什么花哨的,只是简单的切换活动类。我遵循了这个方法,工作起来很有魅力,但让我知道这是一个很好的方法。

{
 this.props.children.map((slide, index) => {
   return React.cloneElement(slide, {
      key: index,
      className: (this.state.currentActiveIndex === index) ?'active' : ''
   });
 })
}
wz1wpwve

wz1wpwve4#

你可以传递一个prop给child,它可以选择要应用的类(或者只传递类名,但这更语义化):

<Parent contentVisible={true}>
  <Child />
</Parent>

在子渲染中:

const classes = [];

if (props.contentVisible)
  classes.push('visible');

<div className={classes.join(' ')} />
zqdjd7g9

zqdjd7g95#

这是类型安全的现代解决方案(Typescript 5.0,React 18.2):

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

当它遇到非对象类型或ReactFragments时,可以直接修改它来做其他事情。例如,一个ReactFragment是一个Iterable,所以你可以迭代它的所有子元素,并给予它一个类,而不是把它 Package 在一个div中。
satisfies语句之所以存在,是因为我认为它们更清楚地说明了正在发生的事情,并且如果底层类型或React API发生变化,它们将揭示一些其他令人讨厌的错误。如果您运行的是低于4.9的Typescript版本,只需删除它们,一切都应该正常工作。

wz8daaqr

wz8daaqr6#

组件的内部渲染方法:

var childClasses = [],
    childClassNames; 
if (condition) {
    childClasses.push('my-class-name'); 
} 
childClassNames = childClasses.join(' ');

return (<div className={childClassNames}>
     .... (your component here)
</div> );

相关问题