我对复合组件设计有疑问。 我有一个定义道具的包装器组件。 我使用Context.Provider使道具可用于子Content组件。我希望Content组件的子代对{answer}做出21的反应。
限制:我想使用功能组件,挂钩,没有Redux,没有Renderprops。没有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>
);
};
答案 0 :(得分:1)
<Wrapper answer={21}>
{/* I want to do this below: <p>the answer is {answer}</p> */}
<Content>
<p>the answer is answer</p>
</Content>
</Wrapper>
因此,显而易见的答案是像<p>the answer is 21</p>
那样直接内联。如果合适,则21可以来自使用两次的变量。基本上,但是App知道它需要使用21,并将其传递到需要的两个地方。
const App = () => {
const answer = 21;
return (
<div className="App">
<Wrapper answer={answer}>
<Content>
<p>the answer is {answer}</p>
</Content>
</Wrapper>
</div>
);
};
但是我猜测您要解决的实际情况是在组件树的较高部分包含了包装器,因此您不知道要传递给<p>
的内容。因此,Content的工作将是从上下文中获取值,然后使用它进行呈现。但是,为此,您需要在Content组件和App组件之间进行双向通信。内容需要告诉应用程序“这是我从上下文中获得的价值”,然后应用程序可以说“这是我要根据该值呈现的内容”。
换句话说,您需要一个渲染道具,但这是您明确排除的一种可能性。如果您愿意接受这种可能性,那么这就是它的样子。
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,
}
答案 1 :(得分:1)
限制:我想使用功能组件,挂钩,没有Redux,没有Renderprops。没有HOC。
渲染道具和HOC并不是问题,而是针对常见React问题的既定解决方案。在需要时不使用它们会导致代码质量差。
一个丑陋的解决方法是使用文本模板,例如<Content><p>the answer is {answer}</p></Content>
并对其进行处理。这是一个硬编码的示例,可与唯一的孩子一起使用:
const Content = ({ children }, ...remainingProps) => {
const wrapperProps = useContext(WrapperContext);
const theOnlyChild = React.cloneElement(children, {},
children.props.children.replace('{answer}`, wrapperProps.answer);
);
return (
<Wrapper>
{theOnlyChild}
</Wrapper>
);
};
<Content>
子级可以嵌套并且具有任意类型,这使得它在实际使用中变得不那么实用,也更加复杂。
这是渲染道具的用例。
answer
是需要在某个时间接收的值。由于在使用范围中没有answer
变量(App
函数),因此应引入一个新的范围函数,在其中可以注入answer
值。这基本上是 render prop 模式及其特例,作为孩子的功能:
const Content = ({ children }, ...remainingProps) => {
const wrapperProps = useContext(WrapperContext);
return (
<Wrapper>
{children(wrapperProps)}
</Wrapper>
);
};
并按如下方式使用:
<Wrapper answer={21}>
<Content>{({ answer }) => (
<p>the answer is {answer}</p>
)}</Content>
</Wrapper>
这基本上就是WrapperContext.Consumer
的目的,因此Wrapper
和Content
组件可能是多余的。