首页 > 解决方案 > 与匿名子组件通信状态

问题描述

仍然很新的反应......我努力理解如何传达一些简单的东西,比如通过组件传递悬停状态。我正在使用 nextjs 和 styled-jsx。

在过去使用普通的旧 CSS 时,我可以编写如下所示的选择器,以在其父元素悬停时更改元素的文本颜色。

.thing:hover .thing__body {
color: red;
}

但是现在 CSS 被隐藏在每个组件中,他们不知道他们的父级发生了什么。

我想我缺少对 React 的基本理解,因为这么简单的事情不可能这么难。

我找到了如何将悬停状态传递给子组件的示例......如果它们被明确包含,但是如果我们只是渲染 {props.children}

//This is just pseudo code, to get the question across
//We are trying to render TestComp
const TestComp = () => {
  return (
    <Thing>
      <Title>Title</Title>
      <Body>Title</Body>
    </Thing>
  );
};

const Thing = (props) => {
  const [hover, setHover] = useState(false);
  //Thing doesn't know the particular components that are going to be in it.
  //It just renders children, but i would like those children to be aware of the hover 
  //state on this Thing component
  return (<div className="thing" onMouseOver={setHover(true)}>
      {props.children}
      <style jsx>{``}</style>
    </div>);
};
const Body = (props) => {
  //HOW DO I....
  //I would like this text to be red when thing is hovered on...
  //I'm not sure how you pass state down from Thing since Thing doesnt 
  //explicitly render this
  return (
    <div className="thing__body">
      {props.children}

      <style jsx>{`
        .thing__body {
          color: black;
        } 
        .thing__body--hover {
          color: red;
        }
      `}</style>
    </div>
  );
};

标签: reactjsnext.js

解决方案


您需要使用React.cloneElement来更新孩子的道具。我根据您的代码整理了一个快速示例。

const Body = ({ hover }) => (
  <div
    style={{
      width: "50px",
      height: "50px",
      backgroundColor: hover ? "red" : "blue"
    }}
  >
    Child!
  </div>
);

const Thing = ({ children }) => {
  const [hover, setHover] = useState(false);
  const childrenArray = React.Children.toArray(children);

  return (
    <div
      className="thing"
      onMouseOver={() => setHover(true)}
      onMouseOut={() => setHover(false)}
    >
      {childrenArray.map(child => React.cloneElement(child, { hover }))}
    </div>
  );
};

const TestComp = () => (
  <Thing>
    <Body />
  </Thing>
);

我们克隆现有Body组件并修改 props 对象以包含我们的hoverprop。确保您使用React.Children.toArray以确保您正在与一系列孩子一起工作,否则事情可能不会按预期进行。希望有帮助!


推荐阅读