我试图找到正确的方法来定义一些组件,这些组件可以以通用的方式使用:
<Parent>
<Child value="1">
<Child value="2">
</Parent>
当然,在父组件和子组件之间呈现有一个逻辑,您可以想象<select>和<option>是这个逻辑的一个例子。
这是为了解决这个问题的一个虚拟实现:
var Parent = React.createClass({
doSomething: function(value) {
},
render: function() {
return (<div>{this.props.children}</div>);
}
});
var Child = React.createClass({
onClick: function() {
this.props.doSomething(this.props.value); // doSomething is undefined
},
render: function() {
return (<div onClick={this.onClick}></div>);
}
});
问题是无论何时使用{this.props。Children}定义一个包装器组件,如何将某些属性传递给它的所有子组件?
给孩子们传递道具。
查看所有其他答案
通过上下文通过组件树传递共享的全局数据
Context被设计用来共享React组件树的“全局”数据,比如当前认证的用户、主题或首选语言。1
免责声明:这是一个更新的答案,前一个使用旧的上下文API
它基于消费者/提供原则。首先,创建上下文
const { Provider, Consumer } = React.createContext(defaultValue);
然后使用via
<Provider value={/* some value */}>
{children} /* potential consumers */
</Provider>
and
<Consumer>
{value => /* render something based on the context value */}
</Consumer>
当提供者的值道具发生变化时,提供者的所有后代消费者都将重新呈现。从提供者到其后代消费者的传播不受shouldComponentUpdate方法的约束,因此即使在祖先组件退出更新时,消费者也会被更新。1
完整的示例,半伪代码。
import React from 'react';
const { Provider, Consumer } = React.createContext({ color: 'white' });
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
value: { color: 'black' },
};
}
render() {
return (
<Provider value={this.state.value}>
<Toolbar />
</Provider>
);
}
}
class Toolbar extends React.Component {
render() {
return (
<div>
<p> Consumer can be arbitrary levels deep </p>
<Consumer>
{value => <p> The toolbar will be in color {value.color} </p>}
</Consumer>
</div>
);
}
}
1 https://facebook.github.io/react/docs/context.html
在我的情况下,React.cloneElement()给了我很多问题,我使用Typescript的函数组件,所以我用孩子(道具)作为一种方式来传递我的道具给我的孩子元素。同样,我的情况非常独特,我必须传递给父组件一个属性,然后基于该属性,它将某些道具传递给子组件。这可以在一个简单的CodeSandbox示例中看到
App.tsx
import "./styles.css";
import Parent from "./Parent";
export default function App() {
return (
<>
<Parent title={"With div wrapper"}>
{({ title }) => <h1>{title}</h1>}
</Parent>
<Parent>
{({ title }) => <h1>{title === undefined && "this is undefined"}</h1>}
</Parent>
</>
);
}
Parent.tsx
export interface ChildrenProps {
title?: string;
}
interface ParentWrapperProps {
children: (title: ChildrenProps) => JSX.Element;
title?: string;
}
const ParentWrapper: React.FC<ParentWrapperProps> = ({ children, title }) => {
return title ? (
<div>{children({ title: title })}</div>
) : (
<>{children({ title: undefined })}</>
);
};
export default ParentWrapper;
如果你有多个想要传递道具的子元素,你可以这样做,使用React.Children.map:
render() {
let updatedChildren = React.Children.map(this.props.children,
(child) => {
return React.cloneElement(child, { newProp: newProp });
});
return (
<div>
{ updatedChildren }
</div>
);
}
如果你的组件只有一个子元素,就不需要映射,你可以直接克隆元素:
render() {
return (
<div>
{
React.cloneElement(this.props.children, {
newProp: newProp
})
}
</div>
);
}
用新道具克隆孩子
你可以使用React。子元素遍历子元素,然后使用React.cloneElement用新道具(浅合并)克隆每个元素。
请参阅代码注释,为什么我不推荐这种方法。
const Child = ({childName, sayHello}) => (
<button onClick={() => sayHello(childName)}>{childName}</button>
);
函数父({children}) {
//我们将sayHello函数传递给子元素。
函数sayHello(childName) {
console.log(' Hello from ${childName} the child ');
}
const childrenWithProps = React.Children。映射(children, child => {
//检查isValidElement是安全的方法,可以避免
// typescript错误。
if (React.isValidElement(child)) {
返回的反应。cloneElement(child, {sayHello});
}
返回的孩子;
});
返回< div > {childrenWithProps} < / div >
}
函数App() {
//这种方法不太类型安全,Typescript不友好
//看起来像你试图渲染' Child '没有' sayHello '。
//这也会让代码的读者感到困惑。
回报(
<父>
<Child childName="Billy" />
<Child childName="Bob" />
父> < /
);
}
ReactDOM。render(<App />, document.getElementById("container"));
< script src = " https://unpkg.com/react@17 umd格式/ react.production.min.js " > < /脚本>
< script src = " https://unpkg.com/react-dom@17 umd格式/ react-dom.production.min.js " > < /脚本>
< div id = "容器" > < / div >
将子函数作为函数调用
或者,你可以通过渲染道具将道具传递给孩子们。在这种方法中,children(可以是children或任何其他道具名)是一个函数,它可以接受你想传递的任何参数,并返回实际的子函数:
const Child = ({childName, sayHello}) => (
<button onClick={() => sayHello(childName)}>{childName}</button>
);
函数父({children}) {
函数sayHello(childName) {
console.log(' Hello from ${childName} the child ');
}
//这个组件的children必须是一个函数
//返回实际的子节点。我们可以通过
//它的参数然后传递给他们作为道具(在这个
//如果我们传递' sayHello ')。
返回< div >{孩子(sayHello)} < / div >
}
函数App() {
// sayHello是我们在Parent中传递的参数
//我们现在传递到Child。
回报(
<父>
{(sayHello) => (
<反应。片段>
<Child childName="Billy" sayHello={sayHello} />
<Child childName="Bob" sayHello={sayHello} />
< /反应。片段>
)}
父> < /
);
}
ReactDOM。render(<App />, document.getElementById("container"));
< script src = " https://unpkg.com/react@17 umd格式/ react.production.min.js " > < /脚本>
< script src = " https://unpkg.com/react-dom@17 umd格式/ react-dom.production.min.js " > < /脚本>
< div id = "容器" > < / div >
我确实努力让列出的答案工作,但失败了。最终,我发现问题在于正确地建立亲子关系。仅仅在其他组件中嵌套组件并不意味着存在父子关系。
例1。亲子关系;
function Wrapper() {
return (
<div>
<OuterComponent>
<InnerComponent />
</OuterComponent>
</div>
);
}
function OuterComponent(props) {
return props.children;
}
function InnerComponent() {
return <div>Hi! I'm in inner component!</div>;
}
export default Wrapper;
例2。嵌套的组件:
function Wrapper() {
return (
<div>
<OuterComponent />
</div>
);
}
function OuterComponent(props) {
return <InnerComponent />
}
function InnerComponent() {
return <div>Hi! I'm in inner component!</div>;
}
export default Wrapper;
如上所述,道具传递在例1中有效。
下面的文章对此进行了解释https://medium.com/@justynazet/passing-props-to-props-children-using-react-cloneelement- andrend-props -pattern-896da70b24f6