Реакция - передача функции на две двери вниз, с параметрами - PullRequest
0 голосов
/ 26 апреля 2018

Я хочу добиться следующего. Компонент должен иметь возможность принимать в качестве опоры параметризованную функцию. Если кнопка внутри компонента нажата, она вызовет функцию с параметром. Ничего сложного в этом нет:

import React, {Component} from 'react';
import {Button, Modal} from 'semantic-ui-react';


class ConfirmationBox extends Component {
  state = {
    modalOpen: false
  };

  handleOpen = () => {
    this.setState({modalOpen: true})
  };

  handleClose = () => {
    this.setState({modalOpen: false})
  };

  handleConfirmation = () => {

    if (this.props.okFunction){
      console.log("calling passed function");
      console.log(this.props.okFunction);
      this.handleClose();
      this.props.okFunction();
    }
    else{
      console.log("no function passed");
      this.handleClose();
    }
  };

  render() {
    return (
      <Modal open={this.state.modalOpen}
             trigger={this.props.trigger}
             onOpen={() => this.handleOpen()}
             onClose={() => this.handleClose()}>

        <Modal.Content><p>{this.props.message}</p></Modal.Content>
        <Modal.Actions>
          <Button positive onClick={() => this.handleClose()}> {this.props.cancelMessage}
          </Button>
          <Button negative onClick={()=>this.handleConfirmation()}> {this.props.okMessage}
          </Button>
        </Modal.Actions>
      </Modal>

    );
  }


}

export default ConfirmationBox;

Передайте функцию из родительского компонента, и она будет работать как положено.

class Parent extends Component {

  //all kinds of stuff obviously redacted

  //define function
  deletePerson(id){ console.log('Person deleted='+id);}

  //inside render function
  render{
    return(
      <ConfirmationBox trigger={<a style={{cursor:"pointer"}}>Delete</a>}
                             message='Are you sure you want to delete this API key?'
                             okMessage="Delete"
                             okFunction={()=>this.deletePerson(id)}
                             cancelMessage="Cancel"

          />

    )}

}

Операция удаления (в настоящее время это, например, консольный журнал) с использованием параметра id выполнена, и модальное окно закрыто.

Проблема возникает, когда я хочу передать функцию из GrandParentElement в ParentElement, где я бы хотел добавить параметр (и) в функцию и затем передать его в ConfirmationBox.

Сначала это тоже все красиво и модно.

class GrandParent extends Component {

  //define function
  deletePerson(id){ console.log('Person deleted='+id);}

  //inside render function
  render{
    return(
      <Parent deleteFunction={this.deletePerson}    />

    )}

}

class Parent extends Component {

  render{
    return(
      <ConfirmationBox trigger={<a style={{cursor:"pointer"}}>Delete</a>}
                             message='Are you sure?'
                             okMessage="Delete"
                             okFunction={()=>this.props.deleteFunction(id)}
                             cancelMessage="Cancel"

          />

    )}

}

Приятно, что он перенаправляет полностью независимую функцию об удаленииPersons из GrandParent в Parent, где он добавляет параметр. Затем параметризованная функция вызывается внутри модальной, если пользователь выбирает (нажимает правую кнопку). Дело в том, зачем мне передавать функцию из GrandParent в Parent, а затем в Modal? Хорошо, потому что GrandParent - это ContainerElement, где выполняются ajax-вызовы и сохраняется состояние, в то время как родительский объект представляет собой PresentationElement, получающий реквизиты от Grandparent. Допустим, список лиц будет представлен, а кнопки, ссылки, значки и т. Д. Будут добавлены в элементы списка, по которым можно щелкнуть, чтобы редактировать / удалять элементы. Поэтому передача функции из GrandParent и добавление параметра в Parent кажется достаточно распространенным шаблоном для нашего ConfirmationBox.

Где тогда проблема?

Как я говорил, GrandParent - это контейнер, который выполняет вызовы ajax и сохраняет состояние. Поэтому ситуация внутри GrandParent может выглядеть гораздо менее

deletePerson(id){ console.log('Person deleted='+id);}

и много чего еще такого

updateState(){
    //do update the state with information from ajax call
}

deletePerson(id){

    ajaxCallToDeletePerson(id);
    //also maybe ajax calls error handling and loading/waiting screens/spinners etc.
    this.updateState;
}

Так что теперь я не могу найти хорошую комбинацию из множества различных способов передачи функций.

Если я пойду с ранее показанным методом <Parent deleteFunction={this.deletePerson}/> внутри GrandParent и <ConfirmationBox okFunction={()=>this.props.deleteFunction(id)} /> внутри Parent. Я перешлю функцию и смогу добавить параметр, но контекст this. для updateState потерян. Поэтому нажатие кнопки внутри модального окна не обновит состояние GrandParent.

Из множества комбинаций различных методов передачи функций и вызовов функций внутри моих трех компонентов (используя необработанные функции, связывание функций в рендере, связывание их внутри конструктора, используя функции стрелок.) Я не нашел работоспособной комбинации, которая бы служила цели передачи функции из GrandParent, чтобы ее можно было вызвать, нажав кнопку внутри ConfirmationBox, находясь в одновременно добавив к нему параметр внутри родительского компонента. Либо я потеряю контекст, необходимый для обновления состояния GrandParent, либо не смогу указать параметр, либо функции будут вызываться при рендеринге. или другое такое неподходящее время, или не вызывается при необходимости. Какие бы комбинации я ни думал о чем-то, это всегда не в порядке.

Я знаю, что это часть, скорее, TLDR, но я хотел бы добавить всю имеющуюся у меня информацию о проблеме. Если кто-то сделал это до сих пор и имеет опыт в JS / React, то я очень рад услышать ваши идеи о том, как проходит Функции down (и / или вызовы функций) должны быть реализованы для того, чтобы это действительно сработало.

Ответы [ 2 ]

0 голосов
/ 26 апреля 2018

Можете ли вы проверить, что я делаю здесь и скажите мне, поможет ли это вам?

Я все еще учусь реагировать и нахожу вашу проблему интересной

Jwu

0 голосов
/ 26 апреля 2018

Я недавно реализовал нечто подобное для модального. Для меня ключ связывал контекст this в компоненте, где он необходим.

Итак, в GrandParent вы устанавливаете конструктор:

 ...
 constructor () {
   super()
   this.state = {deleting: false} // Set up local state if needed
   this.deleteFunction = this.deleteFunction.bind(this) // binds this context to GrandParent component.
 }
 deleteFunction () {
   this.setState({deleting: true}) // or whatever it needs to be
 }
 ...

Затем deleteFunction имеет доступ к локальному состоянию GrandParent.

Если вы передадите его напрямую от Деда до Родителя Ребенку, это должно сработать:

у дедушки: <Parent deleteFunction={this.deleteFunction} />

В родительском: <Child deleteFunction={this.props.deleteFunction} />

у ребенка: onClick={() => this.props.deleteFunction()}

Теперь вы говорили о добавлении параметра в функцию deleteFarent в Parent. Я хотел бы пойти на это, также передав параметр из Parent в Child и затем вызвав функцию с параметром в Child:

у родителей: <Child deleteFunction={this.props.deleteFunction} deleteParam={param}/>

у ребенка: onClick={() => this.props.deleteFunction(this.props.deleteParam)}

...