React.cloneElement:将CSS类添加到子级

jv4diomz  于 2023-08-08  发布在  React
关注(0)|答案(1)|浏览(140)

在一个基本的vite/js/react/mui项目中,我有这样一个简单的结构:

//example1 - does not work
<DemoContainer>
  <DemoChild />
  <DemoChild />
</DemoContainer>

字符串
我想添加一个css类到所有通过cloneElement传入DemoContainer的元素中:

export function DemoContainer({ children }) {
  const redKids = React.Children.map(children, (child) => React.cloneElement(child, {className: "some-class" }));

  return (
    <div>
    {redKids}
    </div>
  );
}

export function DemoChild() {
  return <div/>;
}

// and the content of 'some-class':
.some-class {
  background-color: red;
}

我希望所有的DemoChild元素都有some-class,但事实并非如此。class="some-class"在dom中无处可见...

有趣的是,它可以很好地与简单的div作为孩子:

//example2 - works fine
<DemoContainer>
  <div/>
  <div/>
  <div/>
</DemoContainer>


这是怎么回事为什么它在div上有效,而在DemoChild上无效?我错过了什么?
我做了一个小演示,如果你想玩的问题:Click
蓝色框是DemoChild元素(应该用红色填充),绿色框是简单的div。
提前感谢!
PS:我知道有其他方法可以将样式/类传递给孩子,但请只关注我上面概述的cloneElement方法。

uqzxnwby

uqzxnwby1#

问题

React.cloneElement的前两个参数是:
1.要克隆的元素
1.要应用于元素的props
element参数是div并且props参数是{ className: "some-class" }时,output 是:

<div className="some-class"></div>

字符串
由于上面是一个DOM元素,因此它在DOM中的外观就是这样(className转换为class)。
element参数为DemoChildprops参数为{ className: "some-class" }时,output 为:

<DemoChild className="some-class" />


然而,上面的 output 实际上并不是最终DOM的样子。它将是您的组件返回的任何内容。由于您的原始组件定义(如下)没有在div上设置className,因此div不会获得className

function DemoChild() {
  return (
    <div
      style={{
        height: "50px",
        outline: "2px solid blue",
        marginBottom: "10px"
      }}
    />
  );
}


组件上的prop不会扩展到组件返回的元素上。想象一下,您有一个更复杂的组件,它接受了更多的props,所有的props都分布在它返回的元素上--DOM将是一团乱。

解决方案

您需要确保组件返回的元素从其prop中设置了className

function DemoChild({ className }) {
  return (
    <div
      className={className}
      style={{
        height: "50px",
        outline: "2px solid blue",
        marginBottom: "10px"
      }}
    />
  );
}


完整演示如下:

const { StrictMode } = React;
const { createRoot } = ReactDOM;

function DemoContainer({ children }) {
  const redKids = React.Children.map(children, (child) =>
    React.cloneElement(child, { className: "some-class" })
  );

  return (
    <div
      style={{
        width: "300px",
        height: "300px",
        padding: "5px",
        outline: "2px solid black"
      }}
    >
      {redKids}
    </div>
  );
}

function DemoChild({ className }) {
  return (
    <div
      className={className}
      style={{
        height: "50px",
        outline: "2px solid blue",
        marginBottom: "10px"
      }}
    />
  );
}

function App() {
  return (
    <div className="App">
      <DemoContainer>
        <DemoChild />
        <DemoChild />
        <div
          style={{
            height: "50px",
            outline: "2px solid green",
            marginBottom: "10px"
          }}
        />
        <div
          style={{
            height: "50px",
            outline: "2px solid green",
            marginBottom: "10px"
          }}
        />
      </DemoContainer>
    </div>
  );
}

const root = createRoot(document.getElementById("root"));
root.render(<StrictMode><App /></StrictMode>);
.some-class {
  background-color: red;
}
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="root"></div>

相关问题