如何在 React 中更新父级的状态?

IT技术 javascript reactjs web-deployment
2021-02-08 18:10:27

我的结构如下:

Component 1

 - |- Component 2


 - - |- Component 4


 - - -  |- Component 5

Component 3

组件 3 应根据组件 5 的状态显示一些数据。

由于 props 是不可变的,我不能简单地将它的状态保存在组件 1 中并转发它,对吗?是的,我读过Redux,但我不想使用它。我希望可以通过react来解决它。我错了吗?

6个回答

对于子父通信,您应该传递一个函数来设置从父到子的状态,就像这样


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}/ >
  }
}

通过这种方式,子进程可以通过调用通过 props 传递的函数来更新父进程的状态。

但是您必须重新考虑组件的结构,因为据我了解,组件 5 和 3 不相关。

一种可能的解决方案是将它们包装在更高级别的组件中,该组件将包含组件 1 和 3 的状态。该组件将通过 props 设置较低级别的状态。

这一切都说得通,为什么是 e.preventDefault ?这需要jquery吗?
2021-03-13 18:10:27
快速提问,这是否不允许在子进程中分配本地状态?
2021-03-14 18:10:27
ES6 React 类方法中的@chemook78 不会自动绑定到类。所以如果我们不添加this.handler = this.handler.bind(this)构造函数,函数this内部handler将引用函数闭包,而不是类。如果不想在构造函数中绑定所有函数,还有两种方法可以使用箭头函数来解决这个问题。您可以将点击处理程序编写为onClick={()=> this.setState(...)},或者您可以将属性初始化程序与箭头函数一起使用,如此处babeljs.io/blog/2015/06/07/react-on-es6-plus在“箭头函数”下所述
2021-03-21 18:10:27
为什么你需要 this.handler = this.handler.bind(this) 而不仅仅是设置状态的处理函数?
2021-03-23 18:10:27
这是一个实际的例子:plnkr.co/edit/tGWecotmktae8zjS5yEr?p=preview
2021-03-25 18:10:27

我发现以下工作解决方案将 onClick 函数参数从子组件传递给父组件:

传递方法()的版本

//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")
    );
}

看看JSFiddle

传递箭头函数的版本

//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")
    );
}

看看JSFiddle

这个不错!你能解释一下这篇文章:<ChildB handleToUpdate = {handleToUpdate.bind(this)} />为什么要再次绑定?
2021-03-17 18:10:27
@Dane - 您必须将 this 的上下文绑定为父级,以便this在子级内部调用this指的是父级的状态而不是子级的状态。这是最好的关闭!
2021-03-17 18:10:27
你完全正确!我错过了。是的,如果您已经在构造函数中完成了,那么您就可以开始了!
2021-03-25 18:10:27
@Casey 但我们不是在构造函数中这样做吗?这还不够吗??
2021-03-26 18:10:27
你是传奇搭档!这将使组件很好地自包含,而不必被迫创建父组件来处理状态交换
2021-03-31 18:10:27

这就是我们如何使用新useState钩子来做到这一点方法 - 将状态更改器函数作为props传递给子组件,并对该函数执行任何您想做的事情

import React, {useState} from 'react';

const ParentComponent = () => {
  const[state, setState]=useState('');
  
  return(
    <ChildConmponent stateChanger={setState} />
  )
}


const ChildConmponent = ({stateChanger, ...rest}) => {
  return(
    <button onClick={() => stateChanger('New data')}></button>
  )
}
谢谢。@mylesthe.dev
2021-03-25 18:10:27
不错的现代例子
2021-04-08 18:10:27

我要感谢最受好评的答案给了我我自己的问题的想法,基本上是它与箭头函数的变化和从子组件传递参数:

 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')}/ >
  }
}

希望它可以帮助某人。

与直接调用相比,箭头函数有什么特别之处?
2021-03-16 18:10:27
@AshishKamble thisin 箭头函数指的是父级的上下文(即Parent类)。
2021-03-16 18:10:27
这是一个重复的答案。您可以在已接受的答案中添加评论,并提及此实验性功能以在课堂上使用箭头函数。
2021-03-29 18:10:27
什么是(曾经)最受好评的答案?你可以说得更详细点吗?最高票的答案可能会随着时间的推移而改变。
2021-03-31 18:10:27

我喜欢关于传递函数的答案。这是一个非常方便的技术。

另一方面,您也可以使用 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> 
}

与 Flux 捆绑的调度程序非常简单。它只是注册回调并在任何调度发生时调用它们,传递调度上的内容(在上面的简洁示例中payload,调度没有,只是一个消息 ID)。如果这对您更有意义,您可以非常轻松地将其调整为传统的发布/订阅(例如,使用来自事件的 EventEmitter 或其他版本)。

我的 Reacts 组件像在官方教程(facebook.github.io/react/docs/tutorial.html)中一样在浏览器中“运行”我试图将 Flux 包含在 browserify 中,但浏览器说,找不到 Dispatcher :(
2021-03-11 18:10:27
我使用的语法是 ES2016 module语法,需要转译(我使用Babel,但还有其他的,babelify转换可以browserify一起使用),它转译为var Dispatcher = require( 'flux' ).Dispatcher
2021-03-18 18:10:27