我试图找到正确的方法来定义一些组件,这些组件可以以通用的方式使用:
<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文档《高阶组件》中找到了一篇文章
以下是我的例子:
import React from 'react';
const withForm = (ViewComponent) => {
return (props) => {
const myParam = "Custom param";
return (
<>
<div style={{border:"2px solid black", margin:"10px"}}>
<div>this is poc form</div>
<div>
<ViewComponent myParam={myParam} {...props}></ViewComponent>
</div>
</div>
</>
)
}
}
export default withForm;
const pocQuickView = (props) => {
return (
<div style={{border:"1px solid grey"}}>
<div>this is poc quick view and it is meant to show when mouse hovers over a link</div>
</div>
)
}
export default withForm(pocQuickView);
对我来说,我在实现高阶组件的模式中找到了一个灵活的解决方案。
当然,这取决于功能,但如果其他人正在寻找类似的需求,这是很好的,这比依赖于原始级别的反应代码,如克隆要好得多。
我经常使用的另一种模式是容器模式。一定要读一读,那里有很多文章。
我需要修复上面接受的答案,以使它使用该指针而不是这个指针。在map函数的范围内没有定义doSomething函数。
var Parent = React.createClass({
doSomething: function() {
console.log('doSomething!');
},
render: function() {
var that = this;
var childrenWithProps = React.Children.map(this.props.children, function(child) {
return React.cloneElement(child, { doSomething: that.doSomething });
});
return <div>{childrenWithProps}</div>
}})
更新:此修复适用于ECMAScript 5,在ES6中不需要var that=this