React-您可以将状态处理程序传递到多个子组件层吗

时间:2018-10-13 12:28:58

标签: reactjs

我有一个React父组件,用于保存整个应用程序的状态。我想将一个函数传递给子组件,以便在该子组件中单击按钮时,它将更改父组件的状态。现在,我可以在一层上执行此操作,但是,当我尝试将函数向下传递到另一层(因此,子组件向下传递作为道具接收到的函数)时,我的应用程序将发生以下错误:

TypeError: Cannot read property 'props' of undefined

是否可以将此功能向下传递到多层?

在最低层,我没有设置构造函数,因为我认为只需要我需要在子组件中初始化状态,对吗?

我在下面详细介绍了代码的相关部分:

父母:

  class App extends Component {
  constructor() {
    super();
    this.changeDisplay = this.changeDisplay.bind(this)
    this.handleAddTicket = this.handleAddTicket.bind(this)
    this.handleDeleteTicket = this.handleDeleteTicket.bind(this)

    this.state = {...}
...
}

 handleDeleteTicket(data){
    console.log(data)

  } ....

第一个孩子

class Board extends React.Component {
return (
            <Container>
                <Row>
                    <Col sm={4}>
                        <Todo tasks={todoTasks} deleteTicket={this.props.deleteTicket}/>
                    </Col>
                </Row>
            </Container>
  )
}

第二个孩子:

class Todo extends React.Component {
render() {
todoTicketsAr = this.props.tasks.map(function (obj, i) {
                return <Ticket key={i} data={obj} deleteTicket={this.props.deleteTicket}></Ticket>
            })
        }

        return (
            <div>
                <h2>To do:</h2>
                {todoTicketsAr}
            </div>
                )
    }

所以我要在父级上绑定它,对吗?

2 个答案:

答案 0 :(得分:0)

唯一会发生的时间是因为this不再正确绑定。我可以给出的一种常见情况是:

这将引发错误

class App extends Component {
     someClickHandler() {
         /** 
          * This line will throw an error onClick 
          * of the button because `this` is not bound to the right thing.
          * If you log out `this` you'll probably see the click event object. 
          */
         console.log(this.state); 
     }
     render() {
          return (
              <button onClick={this.someHandler}>Random button</button
          )
     }
}

要正确绑定this,您必须执行任一操作

<button onClick={() => this.someHandler()}>Random button</button>

// or

<button onClick={this.someHandler.bind(this)}>Random button</button>

答案 1 :(得分:0)

这里是如何使用prop钻探和上下文API进行操作的示例。我将使用Context API示例,因为当您需要在不同组件中使用状态的不同部分时,无需保持prop钻探。

如果您想了解该方法的有效性并比较这两种解决方案,我还提供了一个道具钻探示例。

反应上下文API示例

const Global = React.createContext({});

class Store extends React.Component {
  static Consumer = Global.Consumer;
  state = {
    value: 'bacon',
  };
  changeValue = (value) => this.setState({ value });
  render() {
    const { value } = this.state;
    const { changeValue } = this;
    return (
      <Global.Provider value={{
        value,
        changeValue,
      }}>
        {this.props.children}
      </Global.Provider>
    )
  }
}

class Child extends React.Component {
  state = {
    text: '',
  };
  handleChange = (evt) => this.setState({ text: evt.target.value });
  render() {
    const { text } = this.state;
    const { handleChange } = this;
    return (
      <Store.Consumer>
        {({ value, changeValue }) => (
          <div>
            <h3>Value is {value}</h3>
            <h5>Type a new value and submit</h5>
            <input value={text} onChange={handleChange} />
            <button onClick={() => changeValue(text)}>Submit</button>
          </div>
        )}
      </Store.Consumer>
    )
  }
}

const Layout = () => (
  <div>
    <h5>An example component that is not exposed to context</h5>
    <Child/>
  </div>
)

const Main = () => (
  <Store>
    <h2>React Context API example</h2>
    <Layout/>
  </Store>
);

ReactDOM.render(<Main/>, document.body);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

道具钻探示例

const ChildOfChild = ({ toggleDisplay }) => (
  <div>
    <button onClick={toggleDisplay}>Toggle in Child of Child</button>
  </div>
);

const Child = ({ toggleDisplay }) => (
  <div>
    <button onClick={toggleDisplay}>Toggle in Child</button>
    <ChildOfChild toggleDisplay={toggleDisplay} />
  </div>
);

class Main extends React.Component {
  state = {
    display: true,
  };
  toggleDisplay = () => {
    this.setState((prevState) => ({
      display: !prevState.display,
    }));
  };
  render() {
    const { toggleDisplay } = this;
    return (
      <div>
        <h2>React Prop drilling Example</h2>
        <pre>{this.state.display.toString()}</pre>
        <button onClick={this.toggleDisplay}>Parent</button>
        <Child toggleDisplay={toggleDisplay} />
      </div>
    );
  }
}

ReactDOM.render(
  <Main/>,
  document.body
);
<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>