假设我有一个React类P,它呈现两个子类,C1和C2。
C1包含一个输入字段。我将把这个输入字段称为Foo。
我的目标是让C2对Foo中的更改做出反应。
我想出了两个解决办法,但感觉都不太对。
第一个解决方案:
给P分配一个状态state.input。
在P中创建一个onChange函数,它接收一个事件并设置state.input。
将这个onChange作为一个props传递给C1,并让C1将this.props.onChange绑定到Foo的onChange。
这个作品。每当Foo的值发生变化时,它就会触发P中的setState,这样P就有了要传递给C2的输入。
但出于同样的原因,感觉不太对:我正在从子元素设置父元素的状态。这似乎违背了React的设计原则:单向数据流。
这是我应该怎么做,还是有一个更反应自然的解决方案?
第二个解决方案:
把Foo放到P中。
但是,当我构造我的应用程序——把所有表单元素放在最高级别类的渲染中——时,这是我应该遵循的设计原则吗?
就像在我的例子中,如果我有一个C1的大渲染,我真的不想仅仅因为C1有一个表单元素就把C1的整个渲染放到P的渲染中。
我该怎么做呢?
最近的回答有一个例子,它使用React.useState
将状态保存在父组件中是推荐的方法。父组件需要访问它,因为它跨两个子组件管理它。不建议将其移动到全局状态,就像由Redux管理的状态一样,原因与在软件工程中全局变量通常不如局部变量的原因相同。
当状态在父组件中时,如果父组件在props中给了子组件值和onChange处理程序,子组件就可以改变它(有时它被称为值链接或状态链接模式)。下面是你如何用钩子做这件事:
function Parent() {
var [state, setState] = React.useState('initial input value');
return <>
<Child1 value={state} onChange={(v) => setState(v)} />
<Child2 value={state}>
</>
}
function Child1(props) {
return <input
value={props.value}
onChange={e => props.onChange(e.target.value)}
/>
}
function Child2(props) {
return <p>Content of the state {props.value}</p>
}
整个父组件将在子组件的输入更改时重新呈现,如果父组件很小/重新呈现的速度很快,这可能不是问题。在一般情况下(例如大型表单),父组件的重新呈现性能仍然是一个问题。这在你的案例中解决了问题(见下文)。
状态链接模式和无父重渲染使用第三方库更容易实现,如Hookstate -增压React。useState涵盖各种用例,包括您的用例。(声明:我是该项目的作者之一)。
这是胡克州的情况。Child1会改变输入,Child2会对它做出反应。Parent将保留状态,但不会在状态改变时重新呈现,只有Child1和Child2会。
import { useStateLink } from '@hookstate/core';
function Parent() {
var state = useStateLink('initial input value');
return <>
<Child1 state={state} />
<Child2 state={state}>
</>
}
function Child1(props) {
// to avoid parent re-render use local state,
// could use `props.state` instead of `state` below instead
var state = useStateLink(props.state)
return <input
value={state.get()}
onChange={e => state.set(e.target.value)}
/>
}
function Child2(props) {
// to avoid parent re-render use local state,
// could use `props.state` instead of `state` below instead
var state = useStateLink(props.state)
return <p>Content of the state {state.get()}</p>
}
附注:这里还有很多类似的例子,它们涵盖了更复杂的场景,包括深度嵌套数据、状态验证、使用setState钩子的全局状态等等。网上还有一个完整的示例应用程序,它使用了Hookstate和上面解释的技术。
我很惊讶,在我写作的时候,没有一个简单的惯用React解决方案。所以这里是一个(比较大小和复杂性):
class P extends React.Component {
state = { foo : "" };
render(){
const { foo } = this.state;
return (
<div>
<C1 value={ foo } onChange={ x => this.setState({ foo : x })} />
<C2 value={ foo } />
</div>
)
}
}
const C1 = ({ value, onChange }) => (
<input type="text"
value={ value }
onChange={ e => onChange( e.target.value ) } />
);
const C2 = ({ value }) => (
<div>Reacting on value change: { value }</div>
);
我正在从子元素设置父元素的状态。这似乎违背了React的设计原则:单向数据流。
任何受控输入(React中使用表单的惯用方式)在onChange回调中更新父状态,仍然不会泄露任何信息。
例如,仔细看看C1组件。在C1和内置输入组件处理状态变化的方式上,您看到有什么显著的区别吗?你不应该,因为根本就没有。提升状态并传递value/onChange对是原始React的惯用方法。而不是像一些答案所暗示的那样使用裁判。
解释了将数据从父节点传递到子节点的概念,反之亦然。
import React, { Component } from "react";
import ReactDOM from "react-dom";
// taken refrence from https://gist.github.com/sebkouba/a5ac75153ef8d8827b98
//example to show how to send value between parent and child
// props is the data which is passed to the child component from the parent component
class Parent extends Component {
constructor(props) {
super(props);
this.state = {
fieldVal: ""
};
}
onUpdateParent = val => {
this.setState({
fieldVal: val
});
};
render() {
return (
// To achieve the child-parent communication, we can send a function
// as a Prop to the child component. This function should do whatever
// it needs to in the component e.g change the state of some property.
//we are passing the function onUpdateParent to the child
<div>
<h2>Parent</h2>
Value in Parent Component State: {this.state.fieldVal}
<br />
<Child onUpdate={this.onUpdateParent} />
<br />
<OtherChild passedVal={this.state.fieldVal} />
</div>
);
}
}
class Child extends Component {
constructor(props) {
super(props);
this.state = {
fieldValChild: ""
};
}
updateValues = e => {
console.log(e.target.value);
this.props.onUpdate(e.target.value);
// onUpdateParent would be passed here and would result
// into onUpdateParent(e.target.value) as it will replace this.props.onUpdate
//with itself.
this.setState({ fieldValChild: e.target.value });
};
render() {
return (
<div>
<h4>Child</h4>
<input
type="text"
placeholder="type here"
onChange={this.updateValues}
value={this.state.fieldVal}
/>
</div>
);
}
}
class OtherChild extends Component {
render() {
return (
<div>
<h4>OtherChild</h4>
Value in OtherChild Props: {this.props.passedVal}
<h5>
the child can directly get the passed value from parent by this.props{" "}
</h5>
</div>
);
}
}
ReactDOM.render(<Parent />, document.getElementById("root"));
最近的回答有一个例子,它使用React.useState
将状态保存在父组件中是推荐的方法。父组件需要访问它,因为它跨两个子组件管理它。不建议将其移动到全局状态,就像由Redux管理的状态一样,原因与在软件工程中全局变量通常不如局部变量的原因相同。
当状态在父组件中时,如果父组件在props中给了子组件值和onChange处理程序,子组件就可以改变它(有时它被称为值链接或状态链接模式)。下面是你如何用钩子做这件事:
function Parent() {
var [state, setState] = React.useState('initial input value');
return <>
<Child1 value={state} onChange={(v) => setState(v)} />
<Child2 value={state}>
</>
}
function Child1(props) {
return <input
value={props.value}
onChange={e => props.onChange(e.target.value)}
/>
}
function Child2(props) {
return <p>Content of the state {props.value}</p>
}
整个父组件将在子组件的输入更改时重新呈现,如果父组件很小/重新呈现的速度很快,这可能不是问题。在一般情况下(例如大型表单),父组件的重新呈现性能仍然是一个问题。这在你的案例中解决了问题(见下文)。
状态链接模式和无父重渲染使用第三方库更容易实现,如Hookstate -增压React。useState涵盖各种用例,包括您的用例。(声明:我是该项目的作者之一)。
这是胡克州的情况。Child1会改变输入,Child2会对它做出反应。Parent将保留状态,但不会在状态改变时重新呈现,只有Child1和Child2会。
import { useStateLink } from '@hookstate/core';
function Parent() {
var state = useStateLink('initial input value');
return <>
<Child1 state={state} />
<Child2 state={state}>
</>
}
function Child1(props) {
// to avoid parent re-render use local state,
// could use `props.state` instead of `state` below instead
var state = useStateLink(props.state)
return <input
value={state.get()}
onChange={e => state.set(e.target.value)}
/>
}
function Child2(props) {
// to avoid parent re-render use local state,
// could use `props.state` instead of `state` below instead
var state = useStateLink(props.state)
return <p>Content of the state {state.get()}</p>
}
附注:这里还有很多类似的例子,它们涵盖了更复杂的场景,包括深度嵌套数据、状态验证、使用setState钩子的全局状态等等。网上还有一个完整的示例应用程序,它使用了Hookstate和上面解释的技术。