我可以 select 一个类型的所有 React 组件,而无需为每个组件分配 class 吗?

Can I select all react components of a type, without assigning a class to each one?

我这里有个游乐场:https://codesandbox.io/s/736v9vjzw1

const Something = ({ classes, children, variant }) => {
  return (
    <div className={classes.someThing}>
      <p> I'm some thing </p>

      <SomeOtherThing />

      <SomeOtherThing> I have some children </SomeOtherThing>

      <SomeOtherThing> I have some children </SomeOtherThing>

      <SomeOtherThing> I have some children </SomeOtherThing>
    </div>
  );
};

const styles = {
  someThing: {
    color: "green",
    border: "solid 2px black",
    margin: 30,

    "& $someOtherThing": {
      backgroundColor: "pink" // Doesn't work
    },

    "& p": {
      fontWeight: "bold" //This works but is too broad
    }
  }
};

我有一种情况,我想在我的 SomeThing 中设置所有 SomeOtherThing 的样式。

我可以使用 & p select 或 select p 元素 - 但我不喜欢这样。它会为我周围的任何随机 p 设置样式 - 而且我不想查看组件定义内部来查找它的顶级元素是什么。

我该怎么做?类似于 & SomeOtherElement.

这在现实世界中的应用是,在某些地方我想 SomeOtherElement 显示 block 而在其他地方 inline-block

我将扩展 SomeOtherThing 组件以接受 class 名称并将其添加到 div(如果存在)。这也适用于生产设置,其中 class 名称被缩小为例如.t-0-root.

这是一个分叉的游乐场:https://codesandbox.io/s/zlzx277zzm 展示了如何使用它。

const SomeOtherThing = ({ classes, children, className }) => {
  return (
    <p className={`${classes.someOtherThing} ${className && className}`}>
      I'm another thing {children}
    </p>
  );
};

我很可能会使用包 classnames 有条件地呈现 class 名称而不是字符串插值。

const Something = ({ classes, children, variant }) => {
  return (
    <div className={classes.someThing}>
      <p> I'm some thing </p>

      <SomeOtherThing />

      <SomeOtherThing className={classes.someOtherThing}>
        I have some children
      </SomeOtherThing>

      <SomeOtherThing className={classes.someOtherThing}>
        I have some children
      </SomeOtherThing>

      <SomeOtherThing className={classes.someOtherThing}>
        I have some children
      </SomeOtherThing>
    </div>
  );
};

const styles = {
  someThing: {
    color: "green",
    border: "solid 2px black",
    margin: 30
  },
  someOtherThing: {
    backgroundColor: "pink"
  }
};

很简单,在您的 someThing CSS 代码中 select p 元素带有 class someOtherThing class在顶层为 p 命名并使用 not() CSS 操作,请参见以下代码:

const styles = {
  someThing: {
    color: "green",
    border: "solid 2px black",
    margin: 30,

    "& [class*='SomeOtherThing']": {
      backgroundColor: "pink" // 
    },

    "& :not([class*='SomeOtherThing'])": {
      fontWeight: "bold" // Just for top level p
    }
  }
};

const SomeOtherThing = ({ classes, children }) => {
  return (
    <p className={classes.root}> I'm another thing {children} </p>
  );
};

CodeSandBox

它的工作方式是,通过给 SomeOtherThing 任何 jss class,它会将 dom 元素呈现为类似于:

 <p class="SomeOtherThing-root-0-1-2"> I'm another thing  I have some children  </p>

[class*='SomeOtherThing'] attribute selector 将匹配。

您应该注意,此 selector 也将适用于任何更深的嵌套 SomeOtherThings。

"cascading" CSS 方面的一个问题是它有点破坏了 React 的组件模型。但是在 React 中,你总是可以创建一个包装器或高阶组件,returns 另一个带有一些预定义的道具,有点像工厂函数:

const Something = props => {
  return (
    <div className={props.className}>
      // ...
    </div>
  )
}

const SomethingInline = props => {
  return <Something className='display-inline' {...props} />
}

const SomethingBlock = props => {
  return <Something className='display-block' {...props} />
}

const App = () => {
  return (
    <div>
      <SomethingInline />
      <SomethingBlock />
      <SomethingBlock> I have children </SomethingBlock>
    </div>
  )
}

不要使用 & 选择器来定义您的样式,而是创建一个仅适用于组件的这些特定版本的 class。通过这种方式,避免了 CSS 的全局范围,您可以创建这些描述自己样式的声明性组件,但不需要您显式传递 class 名称。