4

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>
  }
}
nem035
  • 34,790
  • 6
  • 87
  • 99
bgmaster
  • 2,313
  • 4
  • 28
  • 41

3 Answers3

4

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
Rob M.
  • 35,491
  • 6
  • 51
  • 50
1

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.

nem035
  • 34,790
  • 6
  • 87
  • 99
0

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>
  );
}
Frazer Kirkman
  • 1,003
  • 1
  • 14
  • 23