简体   繁体   中英

Passing a function down multiple children components in React using ES6

I have a LayoutComponent , PageComponent , and SingleComponent .

When my user clicks a button, I want to display a message to the user on a NewPageComponent that my application routes to using Meteor's FlowRouter .

To do this, I am storing the message in LayoutComponent 's state, and then passing this message and a handlerMethod down as props to the SingleComponent via PageComponent , which is a stateless functional component.

I am not having any luck passing the handlerMethod down properly to the SingleComponent in order to set the message state on LayoutComponent .

I know this is a simple syntax issue, but could someone help me find my error?

LayoutComponent:

export default class LayoutComponent extends Component {
  constructor() {
    super();

    this.state = {
      message: null
    };

    this.handlerMethod = this.handlerMethod.bind(this);
  }

  handlerMethod(message) {
    this.setState({ message: message });
  }

  render() {
    // the PageComponent is actually passed via FlowRouter in this.props.content, so it needs to be cloned to add props
    let contentWithProps = React.cloneElement(this.props.content, { message: this.state.message, handlerMethod: ((message) => this.handlerMethod) });
     return (
       <div>{contentWithProps}</div>
     );
  }
}

PageComponent:

const PageComponent = ({ message, handlerMethod }) => {
  return (
    <div>
      <SingleComponent message={message} handlerMethod={(message) => handlerMethod} />
    </ div>
  );
}

Component:

export default class SingleComponent extends Component {
  constructor() {
    super();

    this.state = {
    };
    this.handleButtonClick = this.handleButtonClick.bind(this);
  }

  handleButtonClick(event) {
    event.preventDefault();
    // do some more stuff...
    this.props.handlerMethod("You pressed the button!");
    FlowRouter.go("newPage");
  }

  render() {
    <div>
      <button onClick={this.handleButtonClick}>button</button>
    </div>
  }
}

You aren't actually calling your handlerMethod in the code you posted. So this:

handlerMethod: ((message) => this.handlerMethod)

Should be either:

handlerMethod: ((message) => this.handlerMethod(message))

Or more simply:

handlerMethod: this.handlerMethod

Your mistake is that you're passing a function that will return this.handlerMethod instead of call it:

handlerMethod: ((message) => this.handlerMethod) // this returns the handlerMethod function, doesn't call it

Should be

handlerMethod: ((message) => this.handlerMethod(message))

You can also pass it directly:

handlerMethod: this.handlerMethod

The reason passing it directly works is because you're binding the context of handlerMethod inside the constructor for LayoutComponent , meaning this inside handlerMethod will be fixed to LayoutComponent ( see Note bellow )

Here's a short example:

Layout Component

export default class LayoutComponent extends Component {
  constructor() {
    // ...
    this.handlerMethod = this.handlerMethod.bind(this); // handler is bound
  }

  handlerMethod(message) {
    // ...
  }

  render() {
    let contentWithProps = React.cloneElement(
      this.props.content, { 
        message: this.state.message, 
        handlerMethod: this.handlerMethod // pass the handler directly
      }
    );

    return <div>{contentWithProps}</div>;
  }
}

Page Component

// pass the handlerMethod directly
const PageComponent = ({ message, handlerMethod }) => {
  return (
    <div>
      <SingleComponent message={message} handlerMethod={handlerMethod} />
    </ div>
  );
}

Single Component

export default class SingleComponent extends Component {

  // ...

  handleButtonClick(event) {
    // ...
    this.props.handlerMethod("You pressed the button!"); // call the passed method here
    // ...
  }

  // ...
}

Note : Technically, you could override bound this by calling new this.handlerMethod but this isn't happening so you're fine.

If you simply want to pass the method down, you do it like this:

const PageComponent = ({ message, handlerMethod }) => {
  return (
    <div>
      <SingleComponent message={message} handlerMethod={handlerMethod} />
    </ div>
  );
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM