Передача функции нескольким дочерним компонентам в React с использованием ES6

#javascript #reactjs #meteor #ecmascript-6 #flow-router

#javascript #reactjs #meteor #ecmascript-6 #поток-маршрутизатор

Вопрос:

У меня есть LayoutComponent , PageComponent и SingleComponent .

Когда мой пользователь нажимает кнопку, я хочу отобразить пользователю сообщение о том, NewPageComponent что мое приложение перенаправляет на использование Meteor FlowRouter .

Для этого я сохраняю сообщение в состоянии LayoutComponent ‘s, а затем передаю это сообщение и a handlerMethod вниз в качестве реквизитов SingleComponent via PageComponent , который является функциональным компонентом без состояния.

Мне не повезло передать handlerMethod вниз должным образом SingleComponent , чтобы установить состояние сообщения включенным LayoutComponent .

Я знаю, что это простая синтаксическая проблема, но не мог бы кто-нибудь помочь мне найти мою ошибку?

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

Компонент страницы:

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

Компонент:

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

Ответ №1:

На самом деле вы не вызываете свою handlerMethod в опубликованном вами коде. Итак, это:

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

Должно быть либо:

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

Или проще:

 handlerMethod: this.handlerMethod
  

Ответ №2:

Ваша ошибка в том, что вы передаете функцию, которая будет возвращать this.handlerMethod вместо того, чтобы вызывать ее:

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

Должно быть

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

Вы также можете передать ее напрямую:

 handlerMethod: this.handlerMethod
  

Причина, по которой передача ее напрямую работает, заключается в том, что вы привязываете контекст handlerMethod внутри конструктора для LayoutComponent , что означает, что this inside handlerMethod будет исправлен на LayoutComponent (см. Примечание ниже)

Вот краткий пример:

Компонент макета

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

Компонент страницы

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

Один компонент

 export default class SingleComponent extends Component {

  // ...

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

  // ...
}
  

Примечание: Технически вы могли бы переопределить bound this путем вызова new this.handlerMethod , но этого не происходит, так что все в порядке.

Ответ №3:

Если вы просто хотите передать метод, вы делаете это следующим образом:

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