简体   繁体   English

反应复合组件 - 如何反应孩子?

[英]React Compound Component - how to Reactify children?

I have a problem with Compound Component Design.我对复合组件设计有疑问。 I have a Wrapper component defining props.我有一个定义 props 的 Wrapper 组件。 I use a Context.Provider to make props available to a child Content component.我使用 Context.Provider 使道具可用于子内容组件。 I would like children of Content component to reactify {answer} to 21.我希望内容组件的孩子将 {answer} 重新定义为 21。

RESTRICTIONS: I would like to use function components, hooks, no Redux, no Renderprops.限制:我想使用函数组件、钩子,没有 Redux,没有 Renderprops。 no HOCs.没有 HOC。

const App = () => {
  return (
    <div className="App">
      <Wrapper answer={21}>
        {/* I want to do this below: <p>the answer is {answer}</p> */}
        <Content>
          <p>the answer is answer</p>
        </Content>
      </Wrapper>
    </div>
  );
};

const WrapperContext = createContext();

const Wrapper = ({ children, ...props }) => {
  return (
    <WrapperContext.Provider
      value={{
        ...props
      }}
    >
      {children}
    </WrapperContext.Provider>
  );
};

const Content = ({ children }, ...remainingProps) => {
  const wrapperProps = useContext(WrapperContext);


  return (
    <Wrapper>
      <Card>
        <div id="dialog-description">
          {children}
        </div>
      </Card>
    </Wrapper>
  );
};

编辑 React-Compound-Component

<Wrapper answer={21}>
  {/* I want to do this below: <p>the answer is {answer}</p> */}
  <Content>
    <p>the answer is answer</p>
  </Content>
</Wrapper>

So, the obvious answer is to just do it inline as in <p>the answer is 21</p> .因此,显而易见的答案是内联进行,如<p>the answer is 21</p> If appropriate, the 21 can come from a variable which gets used twice.如果合适,21 可以来自一个被使用两次的变量。 Basically, however App knows that it needs to use 21, have it pass it in to both places where it's needed.基本上,但是 App 知道它需要使用 21,让它传递到需要它的两个地方。

const App = () => {
  const answer = 21;
  return (
    <div className="App">
      <Wrapper answer={answer}>
        <Content>
          <p>the answer is {answer}</p>
        </Content>
      </Wrapper>
    </div>
  );
};

But i'm guessing the real situation you're trying to solve has the wrapper in a higher part of the component tree, and so you don't know what to pass in to the <p> .但是我猜您要解决的实际情况是在组件树的较高部分有包装器,因此您不知道将什么传递给<p> So Content's job will be to grab the value from context, and then use it to render.所以 Content 的工作是从上下文中获取值,然后使用它来呈现。 But in order to do that, you need two way communication between the Content component and the App component.但是为了做到这一点,您需要在 Content 组件和 App 组件之间进行双向通信。 The Content needs to tell the App "here's the value i got from context", and then the App can say "here's what i want to be rendered given that value".内容需要告诉应用程序“这是我从上下文中获得的值”,然后应用程序可以说“这是给定该值我想要呈现的内容”。

In other words, you need a render prop, but that's something you explicitly excluded as a possibility.换句话说,您需要一个渲染道具,但这是您明确排除的可能性。 If you're willing to entertain that possibility, here's what it would look like.如果你愿意接受这种可能性,这就是它的样子。

const App = () => {
  return (
    <div className="App">
      <Wrapper answer={21}>
        <Content>
          {({ answer }) => <p>the answer is {answer}</p>}
        </Content>
      </Wrapper>
    </div>
  );
};

const Content = ({ children }, ...remainingProps) => {
  const wrapperProps = useContext(WrapperContext);


  return (
    <Wrapper>
      <Card>
        <div id="dialog-description">
          {children(wrapperProps)}
        </div>
      </Card>
    </Wrapper>
  );
};

Content.propTypes = {
  children: PropTypes.func.isRequired,
}

RESTRICTIONS: I would like to use function components, hooks, no Redux, no Renderprops.限制:我想使用函数组件、钩子,没有 Redux,没有 Renderprops。 no HOCs.没有 HOC。

Render props and HOCs are not a matter of taste but established solutions to common React problems.渲染道具和 HOC 不是品味问题,而是常见 React 问题的既定解决方案。 Not using them when they are needed will result in poor quality code.在需要时不使用它们会导致代码质量低下。

The ugly workaround is to use text templates like <Content><p>the answer is {answer}</p></Content> and process them.丑陋的解决方法是使用像<Content><p>the answer is {answer}</p></Content>这样的文本模板并处理它们。 Here's an example that is hard-coded to be used with the only child:这是一个硬编码的例子,用于唯一的孩子:

const Content = ({ children }, ...remainingProps) => {
  const wrapperProps = useContext(WrapperContext);
  const theOnlyChild = React.cloneElement(children, {}, 
    children.props.children.replace('{answer}`, wrapperProps.answer);
  );

  return (
    <Wrapper>
      {theOnlyChild}
    </Wrapper>
  );
};

That <Content> children can be nested and have arbitrary types makes it even less practical and more complex for real-world use. <Content>子项可以嵌套并具有任意类型,这使得它在现实世界中的使用更加不实用且更加复杂。

This is the use case for render props.这是渲染道具的用例。

answer is a value that needs to be received at some time. answer是需要在某个时间接收的值。 Since there's no answer variable in the scope where it's used ( App function), a new scope function should be introduced where answer value could be injected.由于在使用它的作用域( App函数)中没有answer变量,因此应该在可以注入answer值的地方引入一个新的作用域函数。 This is basically what render prop pattern and its special case, function as child does:这基本上是渲染道具模式及其特殊情况,作为孩子的功能:

const Content = ({ children }, ...remainingProps) => {
  const wrapperProps = useContext(WrapperContext);

  return (
    <Wrapper>
      {children(wrapperProps)}
    </Wrapper>
  );
};

And used like:并使用如下:

  <Wrapper answer={21}>
    <Content>{({ answer }) => (
      <p>the answer is {answer}</p>
    )}</Content>
  </Wrapper>

This is basically what WrapperContext.Consumer is for, so Wrapper and Content components may be redundant.这基本上就是WrapperContext.Consumer的用途,因此WrapperContent组件可能是多余的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM