在下面的代码中,当在 AddressWrapper 中选中复选框时,应禁用 AddressForm 中的 Ship To 输入。我不明白为什么 AddressWrapper cloneElement 没有将它的状态传递给 child 。我已经检查了很多关于这个问题的链接,据我所知这应该有效。这是最近的 How to pass props to {this.props.children}对于这个问题,但它正在使用从 child 到 parent 的回调,我需要改变 parent 的状态来更新 child 。我可以使用发布/订阅来完成它,但我正在尝试以“React”方式进行。
class AddressForm extends React.Component {
constructor(props) {
super(props);
this.state = {
firstName: "Joyce",
disableInputs: props.billToSameAsShipTo
};
this.handleBillToSameAsShipToChanged = this.handleBillToSameAsShipToChanged.bind(
this
);
}
handleBillToSameAsShipToChanged() {
this.setState({ billToSameAsShipTo: !this.state.billToSameAsShipTo });
}
handleFirstNameChanged(ev) {
this.setState({ firstName: ev.target.value });
}
render() {
return (
<form>
<div className="form-row">
<div className="col-6">
<input
type="text"
className="form-control"
placeholder="First name"
disabled={this.state.disableInputs}
value={this.state.firstName}
onChange={this.handleFirstNameChanged.bind(this)}
/>
</div>
</div>
</form>
);
}
}
class AddressFormWrapper extends React.Component {
constructor(props) {
super(props);
this.state = {
billToSameAsShipTo: true
};
this.handlebillToSameAsShipToChanged = this.handlebillToSameAsShipToChanged.bind(
this
);
}
handlebillToSameAsShipToChanged() {
this.setState({ billToSameAsShipTo: !this.state.billToSameAsShipTo });
}
render() {
const billToSameAsShipTo = () => {
if (this.props.showSameAsShipTo === true) {
return (
<span style={{ fontSize: "10pt", marginLeft: "20px" }}>
<input
type="checkbox"
checked={this.state.billToSameAsShipTo}
onChange={this.handlebillToSameAsShipToChanged}
/>
<span>Same as Ship To</span>
</span>
);
}
};
const childWithProp = React.Children.map(this.props.children, child => {
return React.cloneElement(child, { ...this.state });
});
return (
<span className="col-6">
<h3>
{this.props.title}
{billToSameAsShipTo()}
</h3>
<span>{childWithProp}</span>
</span>
);
}
}
const Checkout = () => {
return (
<div>
<br />
<br />
<div className="row">
<AddressFormWrapper title="Ship To" showSameAsShipTo={false}>
<span className="col-6">
<AddressForm />
</span>
</AddressFormWrapper>
<AddressFormWrapper title="Bill To" showSameAsShipTo={true}>
<span className="col-6">
<AddressForm />
</span>
</AddressFormWrapper>
</div>
</div>
);
};
最佳答案
在 AddressFormWrapper
中,您映射到子项并使用 cloneElement()
传递 Prop 。
根据 DOCS :
Invokes a function on every immediate child contained within children...
但仔细看看 AddressFormWrapper
的那些(直接)子级是谁:
<AddressFormWrapper title="Bill To" showSameAsShipTo={true}>
<span className="col-6">
<AddressForm />
</span>
</AddressFormWrapper>
在这种情况下,它是 span
元素而不是 AddressForm
。
如果你像这样渲染它,它将按预期工作:
<AddressFormWrapper title="Bill To" showSameAsShipTo={true}>
<AddressForm />
</AddressFormWrapper>
另一件需要注意的事情是,在 AddressForm
中您正在设置状态:
disableInputs: props.billToSameAsShipTo
这是在 constructor
中,它只会运行一次。所以它会得到初始值但不会改变。
在 componentDidUpdate 中更新它或者更好的是直接使用 Prop :
disabled={this.props.billToSameAsShipTo}
这是一个运行示例:
class AddressForm extends React.Component {
constructor(props) {
super(props);
this.state = {
firstName: "Joyce",
disableInputs: props.billToSameAsShipTo
};
this.handleBillToSameAsShipToChanged = this.handleBillToSameAsShipToChanged.bind(
this
);
}
handleBillToSameAsShipToChanged() {
this.setState({ billToSameAsShipTo: !this.state.billToSameAsShipTo });
}
handleFirstNameChanged(ev) {
this.setState({ firstName: ev.target.value });
}
billToSameAsShipTo() {
if (this.props.showSameAsShipTo === true) {
return (
<span style={{ fontSize: "10pt" }}>
<input
type="checkbox"
checked={this.state.billToSameAsShipTo}
onChange={this.handleBillToSameAsShipToChanged}
/> <span>Same as Ship To</span>
</span>
);
}
}
render() {
return (
<form>
<div className="form-row">
<div className="col-6">
<input
type="text"
className="form-control"
placeholder="First name"
disabled={this.props.billToSameAsShipTo}
value={this.state.firstName}
onChange={this.handleFirstNameChanged.bind(this)}
/>
</div>
</div>
</form>
);
}
}
class AddressFormWrapper extends React.Component {
constructor(props) {
super(props);
this.state = {
billToSameAsShipTo: true
};
this.handlebillToSameAsShipToChanged = this.handlebillToSameAsShipToChanged.bind(
this
);
}
handlebillToSameAsShipToChanged() {
this.setState({ billToSameAsShipTo: !this.state.billToSameAsShipTo });
}
render() {
const billToSameAsShipTo = () => {
if (this.props.showSameAsShipTo === true) {
return (
<span style={{ fontSize: "10pt", marginLeft: "20px" }}>
<input
type="checkbox"
checked={this.state.billToSameAsShipTo}
onChange={this.handlebillToSameAsShipToChanged}
/> <span>Same as Ship To</span>
</span>
);
}
};
const childWithProp = React.Children.map(this.props.children, child => {
return React.cloneElement(child, { ...this.state });
});
return (
<span className="col-6">
<h3>
{this.props.title}
{billToSameAsShipTo()}
</h3>
<span>{childWithProp}</span>
</span>
);
}
}
const Checkout = () => {
return (
<div>
<br />
<br />
<div className="row">
<AddressFormWrapper title="Ship To" showSameAsShipTo={false}>
<span className="col-6">
<AddressForm />
</span>
</AddressFormWrapper>
<AddressFormWrapper title="Bill To" showSameAsShipTo={true}>
<AddressForm />
</AddressFormWrapper>
</div>
</div>
);
};
ReactDOM.render(<Checkout />, document.querySelector("#app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"/>
关于javascript - 使用 cloneElement 将 Props 从父组件传递给子组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53132761/