Javascript 如何在 React 中更新父状态?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/35537229/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to update parent's state in React?
提问by wklm
My structure looks as follows:
我的结构如下:
Component 1
- |- Component 2
- - |- Component 4
- - - |- Component 5
Component 3
Component 3 should display some data depending on state of Component 5. Since props are immutable, I can't simply save it's state in Component 1 and forward it, right? And yes, I've read about redux, but don't want to use it. I hope that it's possible to solve it just with react. Am I wrong?
组件 3 应该根据组件 5 的状态显示一些数据。由于 props 是不可变的,我不能简单地将它的状态保存在组件 1 中并转发它,对吗?是的,我读过关于 redux,但不想使用它。我希望可以通过反应来解决它。我错了吗?
回答by Ivan
For child-parent communication you should pass a function setting the state from parent to child, like this
对于子父通信,您应该传递一个函数来设置从父到子的状态,就像这样
class Parent extends React.Component {
constructor(props) {
super(props)
this.handler = this.handler.bind(this)
}
handler() {
this.setState({
someVar: 'some value'
})
}
render() {
return <Child handler = {this.handler} />
}
}
class Child extends React.Component {
render() {
return <Button onClick = {this.props.handler}/ >
}
}
This way the child can update the parent's state with the call of a function passed with props.
通过这种方式,子进程可以通过调用通过 props 传递的函数来更新父进程的状态。
But you will have to rethink your components' structure, because as I understand components 5 and 3 are not related.
但是您必须重新考虑组件的结构,因为据我了解,组件 5 和 3 不相关。
One possible solution is to wrap them in a higher level component which will contain the state of both component 1 and 3. This component will set the lower level state through props.
一种可能的解决方案是将它们包装在一个更高级别的组件中,该组件将包含组件 1 和 3 的状态。该组件将通过 props 设置较低级别的状态。
回答by Roman
I found the following working solution to pass onClick function argument from child to the parent component:
我发现以下工作解决方案将 onClick 函数参数从子组件传递给父组件:
Version with passing a method()
传递方法()的版本
//ChildB component
class ChildB extends React.Component {
render() {
var handleToUpdate = this.props.handleToUpdate;
return (<div><button onClick={() => handleToUpdate('someVar')}>
Push me
</button>
</div>)
}
}
//ParentA component
class ParentA extends React.Component {
constructor(props) {
super(props);
var handleToUpdate = this.handleToUpdate.bind(this);
var arg1 = '';
}
handleToUpdate(someArg){
alert('We pass argument from Child to Parent: ' + someArg);
this.setState({arg1:someArg});
}
render() {
var handleToUpdate = this.handleToUpdate;
return (<div>
<ChildB handleToUpdate = {handleToUpdate.bind(this)} /></div>)
}
}
if(document.querySelector("#demo")){
ReactDOM.render(
<ParentA />,
document.querySelector("#demo")
);
}
Version with passing an Arrow function
传递箭头函数的版本
//ChildB component
class ChildB extends React.Component {
render() {
var handleToUpdate = this.props.handleToUpdate;
return (<div>
<button onClick={() => handleToUpdate('someVar')}>
Push me
</button>
</div>)
}
}
//ParentA component
class ParentA extends React.Component {
constructor(props) {
super(props);
}
handleToUpdate = (someArg) => {
alert('We pass argument from Child to Parent: ' + someArg);
}
render() {
return (<div>
<ChildB handleToUpdate = {this.handleToUpdate} /></div>)
}
}
if(document.querySelector("#demo")){
ReactDOM.render(
<ParentA />,
document.querySelector("#demo")
);
}
回答by Ardhi
I want to thank the most upvoted answer for giving me the idea of my own problem basically the variation of it with arrow function and passing param from child component:
我要感谢最受好评的答案给了我我自己的问题的想法,基本上是它与箭头函数的变化和从子组件传递参数:
class Parent extends React.Component {
constructor(props) {
super(props)
// without bind, replaced by arrow func below
}
handler = (val) => {
this.setState({
someVar: val
})
}
render() {
return <Child handler = {this.handler} />
}
}
class Child extends React.Component {
render() {
return <Button onClick = {() => this.props.handler('the passing value')}/ >
}
}
Hope it helps someone.
希望它可以帮助某人。
回答by Matt Styles
I like the answer regarding passing functions around, its a very handy technique.
我喜欢关于传递函数的答案,这是一种非常方便的技术。
On the flip side you can also achieve this using pub/sub or using a variant, a dispatcher, as Fluxdoes. The theory is super simple, have component 5 dispatch a message which component 3 is listening for. Component 3 then updates its state which triggers the re-render. This requires stateful components, which, depending on your viewpoint, may or may not be an anti-pattern. I'm against them personally and would rather that something else is listening for dispatches and changes state from the very top-down (Redux does this, but adds additional terminology).
另一方面,您也可以使用 pub/sub 或使用变体、调度程序来实现这一点,就像Flux一样。理论非常简单,让组件 5 发送组件 3 正在侦听的消息。然后组件 3 更新其触发重新渲染的状态。这需要有状态的组件,根据您的观点,它可能是也可能不是反模式。我个人反对他们,宁愿其他东西从上到下监听调度和更改状态(Redux 这样做,但添加了额外的术语)。
import { Dispatcher } from flux
import { Component } from React
const dispatcher = new Dispatcher()
// Component 3
// Some methods, such as constructor, omitted for brevity
class StatefulParent extends Component {
state = {
text: 'foo'
}
componentDidMount() {
dispatcher.register( dispatch => {
if ( dispatch.type === 'change' ) {
this.setState({ text: 'bar' })
}
}
}
render() {
return <h1>{ this.state.text }</h1>
}
}
// Click handler
const onClick = event => {
dispatcher.dispatch({
type: 'change'
})
}
// Component 5 in your example
const StatelessChild = props => {
return <button onClick={ onClick }>Click me</button>
}
The dispatcher bundles with Flux is very simple, it simply registers callbacks and invokes them when any dispatch occurs, passing through the contents on the dispatch (in the above terse example there is no payload
with the dispatch, simply a message id). You could adapt this to traditional pub/sub (e.g. using the EventEmitter from events, or some other version) very easily if that makes more sense to you.
与 Flux 捆绑的调度程序非常简单,它只是注册回调并在任何调度发生时调用它们,传递调度上的内容(在上面的简洁示例中payload
,调度没有,只是一个消息 ID)。如果这对您更有意义,您可以非常轻松地将其调整为传统的发布/订阅(例如,使用事件中的 EventEmitter 或其他版本)。
回答by H. parnian
I found the following working solution to pass onClick function argument from child to the parent component with param:
我找到了以下工作解决方案,将 onClick 函数参数从子组件传递给带有 param 的父组件:
parent class :
父类:
class Parent extends React.Component {
constructor(props) {
super(props)
// Bind the this context to the handler function
this.handler = this.handler.bind(this);
// Set some state
this.state = {
messageShown: false
};
}
// This method will be sent to the child component
handler(param1) {
console.log(param1);
this.setState({
messageShown: true
});
}
// Render the child component and set the action property with the handler as value
render() {
return <Child action={this.handler} />
}}
child class :
儿童班:
class Child extends React.Component {
render() {
return (
<div>
{/* The button will execute the handler function set by the parent component */}
<Button onClick={this.props.action.bind(this,param1)} />
</div>
)
} }
回答by Rajan Twanabashu
When ever you require to communicate between child to parent at any level down, then it's better to make use of context. In parent component define the context that can be invoked by the child such as
当您需要在任何级别的孩子与父母之间进行交流时,最好使用 context。在父组件中定义子组件可以调用的上下文,例如
In parent component in your case component 3
在您的案例组件 3 的父组件中
static childContextTypes = {
parentMethod: React.PropTypes.func.isRequired
};
getChildContext() {
return {
parentMethod: (parameter_from_child) => this.parentMethod(parameter_from_child)
};
}
parentMethod(parameter_from_child){
// update the state with parameter_from_child
}
Now in child component (component 5 in your case) , just tell this component that it want to use context of its parent.
现在在子组件(在您的情况下是组件 5)中,只需告诉这个组件它想要使用其父组件的上下文。
static contextTypes = {
parentMethod: React.PropTypes.func.isRequired
};
render(){
return(
<TouchableHighlight
onPress={() =>this.context.parentMethod(new_state_value)}
underlayColor='gray' >
<Text> update state in parent component </Text>
</TouchableHighlight>
)}
you can find Demo project at repo
你可以在repo找到 Demo 项目
回答by Vishal Bisht
It seems that we can only pass data from parent to child as react promotes Unidirectional Data Flow, but to make parent update itself when something happens in its "child component", we generally use what is called a "callback function".
似乎我们只能将数据从父级传递给子级,因为 React 促进了单向数据流,但是为了在父级组件的“子组件”发生某些事情时更新自身,我们通常使用所谓的“回调函数”。
We pass the function defined in the parent to the child as "props" and call that function from the child triggering it in the parent component.
我们将在父组件中定义的函数作为“道具”传递给子组件,并从子组件调用该函数在父组件中触发它。
class Parent extends React.Component {
handler = (Value_Passed_From_SubChild) => {
console.log("Parent got triggered when a grandchild button was clicked");
console.log("Parent->Child->SubChild");
console.log(Value_Passed_From_SubChild);
}
render() {
return <Child handler = {this.handler} />
}
}
class Child extends React.Component {
render() {
return <SubChild handler = {this.props.handler}/ >
}
}
class SubChild extends React.Component {
constructor(props){
super(props);
this.state = {
somethingImp : [1,2,3,4]
}
}
render() {
return <button onClick = {this.props.handler(this.state.somethingImp)}>Clickme<button/>
}
}
React.render(<Parent />,document.getElementById('app'));
HTML
----
<div id="app"></div>
In this example we can make data pass from SubChild -> Child -> Parent by passing function to its direct Child.
在这个例子中,我们可以通过将函数传递给它的直接 Child 来使数据从 SubChild -> Child -> Parent 传递。
回答by Александр Немков
I've used a top rated answer from this page many times, but while learning React, i've found a better way to do that, without binding and without inline function inside props.
我已经多次使用此页面上评价最高的答案,但是在学习 React 的过程中,我找到了一种更好的方法来做到这一点,在 props 中没有绑定和内联函数。
Just look here:
看看这里:
class Parent extends React.Component {
constructor() {
super();
this.state={
someVar: value
}
}
handleChange=(someValue)=>{
this.setState({someVar: someValue})
}
render() {
return <Child handler={this.handleChange} />
}
}
export const Child = ({handler}) => {
return <Button onClick={handler} />
}
The key is in an arrow function:
关键在于箭头函数:
handleChange=(someValue)=>{
this.setState({someVar: someValue})
}
You can read more here. Hope this will be useful for somebody =)
您可以在此处阅读更多内容。希望这对某人有用 =)
回答by Sachin Metkari
-We can create ParentComponent and with handleInputChange method to update the ParentComponent state. Import the ChildComponent and we pass two props from parent to child component ie.handleInputChange function and count.
- 我们可以创建 ParentComponent 并使用 handleInputChange 方法来更新 ParentComponent 状态。导入 ChildComponent ,我们将两个 props 从父组件传递给子组件 ie.handleInputChange 函数和计数。
import React, { Component } from 'react';
import ChildComponent from './ChildComponent';
class ParentComponent extends Component {
constructor(props) {
super(props);
this.handleInputChange = this.handleInputChange.bind(this);
this.state = {
count: '',
};
}
handleInputChange(e) {
const { value, name } = e.target;
this.setState({ [name]: value });
}
render() {
const { count } = this.state;
return (
<ChildComponent count={count} handleInputChange={this.handleInputChange} />
);
}
}
Now we create the ChildComponent file and save as ChildComponent.jsx. This component is stateless because the child component doesn't have a state. We use the prop-types library for props type checking.
import React from 'react'; import { func, number } from 'prop-types'; const ChildComponent = ({ handleInputChange, count }) => ( <input onChange={handleInputChange} value={count} name="count" /> ); ChildComponent.propTypes = { count: number, handleInputChange: func.isRequired, }; ChildComponent.defaultProps = { count: 0, }; export default ChildComponent;
现在我们创建 ChildComponent 文件并保存为 ChildComponent.jsx。这个组件是无状态的,因为子组件没有状态。我们使用 prop-types 库进行 props 类型检查。
import React from 'react'; import { func, number } from 'prop-types'; const ChildComponent = ({ handleInputChange, count }) => ( <input onChange={handleInputChange} value={count} name="count" /> ); ChildComponent.propTypes = { count: number, handleInputChange: func.isRequired, }; ChildComponent.defaultProps = { count: 0, }; export default ChildComponent;
回答by Pato Loco
If this same scenario is not spread everywhere you can use React's context, specially if you don't want to introduce all the overhead that state management libraries introduce. Plus, it's easier to learn. But be careful, you could overuse it and start writing bad code. Basically you define a Container component (that will hold and keep that piece of state for you) making all the components interested in writing/reading that piece of data its children (not necessarily direct children)
如果同样的场景没有到处传播,你可以使用 React 的上下文,特别是如果你不想引入状态管理库引入的所有开销。此外,它更容易学习。但要小心,你可能会过度使用它并开始编写糟糕的代码。基本上,您定义了一个 Container 组件(它将为您保存并保持该状态)使所有有兴趣写入/读取该数据的组件成为其子级(不一定是直接子级)
https://reactjs.org/docs/context.html
https://reactjs.org/docs/context.html
You could also use plain React properly instead.
您也可以正确地使用普通 React。
<Component5 onSomethingHappenedIn5={this.props.doSomethingAbout5} />
pass doSomethingAbout5 up to Component 1
将 doSomethingAbout5 传递给组件 1
<Component1>
<Component2 onSomethingHappenedIn5={somethingAbout5 => this.setState({somethingAbout5})}/>
<Component5 propThatDependsOn5={this.state.somethingAbout5}/>
<Component1/>
If this a common problem you should starting thinking moving the whole state of the application to someplace else. You have a few options, the most common are:
如果这是一个常见问题,您应该开始考虑将应用程序的整个状态移动到其他地方。您有几个选择,最常见的是:
https://facebook.github.io/flux/
https://facebook.github.io/flux/
Basically, instead of managing the application state in your component you send commands when something happens to get the state updated. Components pull the state from this container as well so all the data is centralized. This doesn't mean can't use local state anymore, but that's a more advanced topic.
基本上,不是在组件中管理应用程序状态,而是在发生状态更新时发送命令。组件也从这个容器中提取状态,所以所有的数据都是集中的。这并不意味着不能再使用本地状态,但这是一个更高级的主题。