我的结构如下所示:

Component 1

 - |- Component 2


 - - |- Component 4


 - - -  |- Component 5

Component 3

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

因为道具是不可变的,我不能简单地在组件1中保存它的状态并转发它,对吗?是的,我读过Redux,但我不想使用它。我希望只用react就能解决这个问题。我错了吗?


当前回答

下面是获得两种绑定数据方式的简短代码片段。

计数器显示来自父进程的值,并从子进程更新

class Parent extends React.Component { constructor(props) { super(props) this.handler = this.handler.bind(this) this.state = { count: 0 } } handler() { this.setState({ count: this.state.count + 1 }) } render() { return <Child handler={this.handler} count={this.state.count} /> } } class Child extends React.Component { render() { return <button onClick={this.props.handler}>Count {this.props.count}</button> } } ReactDOM.render(<Parent />, document.getElementById("root")); <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script> <div id="root"></div>

其他回答

我想感谢得到最多赞的回答,因为他给了我自己的问题的想法,基本上是用箭头函数和从子组件传递参数的变化:

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

希望它能帮助到别人。

这是如何使用新的useState钩子。

方法-将状态改变器函数作为道具传递给子组件,并对该函数做任何你想做的事情:

import React, {useState} from 'react';

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


const ChildComponent = ({stateChanger, ...rest}) => {
  return(
    <button onClick={() => stateChanger('New data')}></button>
  )
}

如果你想要更新父组件,

class ParentComponent extends React.Component {
    constructor(props){
        super(props);
        this.state = {
           page: 0
        }
    }

    handler(val){
        console.log(val) // 1
    }

    render(){
        return (
            <ChildComponent onChange={this.handler} />
        )
    }
}


class ChildComponent extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
             page: 1
        };
    }

    someMethod = (page) => {
        this.setState({ page: page });
        this.props.onChange(page)
    }

    render() {
        return (
            <Button
                onClick={() => this.someMethod()}
            > Click
        </Button>
      )
   }
}

这里的onChange是一个带有“handler”方法绑定到其实例的属性。我们将方法处理程序传递给子类组件,通过props参数中的onChange属性接收。

onChange属性将在props对象中设置,如下所示:

props = {
    onChange: this.handler
}

并传递给子组件。

所以子组件可以像props. onchange这样访问props对象中的name值。

这是通过使用渲染道具完成的。

现在子组件有一个按钮“Click”,带有一个onclick事件集,用于调用通过props参数对象中的onChange传递给它的处理程序方法。所以现在子类中的this.props.onChange保存了父类中的输出方法。

参考资料和演职员表:Bits and Pieces

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

On the flip side you can also achieve this using pub/sub or using a variant, a dispatcher, as Flux does. 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 it adds additional terminology).

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的调度程序捆绑非常简单。它只是简单地注册回调,并在任何分派发生时调用它们,传递分派上的内容(在上面的简洁示例中,分派没有有效负载,只有一个消息id)。如果对您更有意义的话,您可以很容易地将其调整为传统的pub/sub(例如,从事件中使用EventEmitter或其他版本)。

如果同样的场景不是到处都有,你可以使用React的上下文,特别是如果你不想引入状态管理库所引入的所有开销。另外,它更容易学习。但是要小心;你可能会过度使用它并开始编写糟糕的代码。基本上,你定义了一个Container组件(它将保存并为你保存这段状态),使得所有的组件都对从它的子组件(不一定是直接的子组件)写入/读取这段数据感兴趣。

背景信息-反应

你也可以使用一个普通的React来代替。

<Component5 onSomethingHappenedIn5={this.props.doSomethingAbout5} />

将doSomethingAbout5传递给组件1:

<Component1>
    <Component2 onSomethingHappenedIn5={somethingAbout5 => this.setState({somethingAbout5})}/>
    <Component5 propThatDependsOn5={this.state.somethingAbout5}/>
<Component1/>

如果这是一个常见问题,那么您应该开始考虑将应用程序的整个状态转移到其他地方。你有几个选择,最常见的是:

回来的 通量

基本上,不是在组件中管理应用程序状态,而是在发生更新状态的情况时发送命令。组件也从这个容器中提取状态,因此所有数据都是集中的。这并不意味着您不能再使用局部状态,但这是一个更高级的主题。