简体   繁体   English

反应-将功能向下传递两扇门,并带有参数

[英]React - passing a function two doors down, with parameters

I want to achieve the following. 我要实现以下目标。 Component should be able to take as a prop a parametrized function. 组件应能够支持参数化功能。 In case a button inside the component is pressed it will call the function with the parameter. 如果按下组件内部的按钮,它将使用参数调用该函数。 Nothing complicated about that: 没什么复杂的:

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;

Pass in a function from the parent component and it works as expected. 从父组件传递一个函数,它可以按预期工作。

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"

          />

    )}

}

The delete action (currently just a console log for example) using id parameter is done and modal is closed. 使用id参数的删除操作(例如,目前仅是控制台日志)已完成,并且模式已关闭。

The problem arises when I want to pass the function from a GrandParentElement to ParentElement, where I'd want to add parameter(s) to the function and then pass it to the ConfirmationBox. 当我想将函数从GrandParentElement传递给ParentElement时,会出现问题,在这里我想向函数中添加参数,然后将其传递给ConfirmationBox。

At first it is also all nice and dandy. 刚开始的时候,一切都很好。

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"

          />

    )}

}

Nicely it forwards a totally independent function about deletingPersons from GrandParent to Parent, where it adds a parameter. 很好地,它转发了一个有关DeletePersons从GrandParent到Parent的完全独立的函数,在该函数中添加了参数。 Then the parametrized function is called inside modal if the user so chooses (clicks the right button). 然后,如果用户选择(单击右键),则在模态内部调用参数化函数。 The thing is - why would I want to pass a function from GrandParent to Parent and then to Modal? 问题是-为什么我要从GrandParent传递函数给Parent,然后传递给Modal? Well because GrandParent is a ContainerElement where ajax calls are made and state kept, while the parent is a PresentationElement receiving props from Grandparent. 好吧,因为GrandParent是一个用于进行ajax调用并保持状态的ContainerElement,而父级是一个PresentationElement,用于接收来自Grandparent的道具。 The list of lets say persons will be presented and buttons, links, icons etc. will be added to list elements on which to click to edit/delete items. 可以说出人物的列表,然后将按钮,链接,图标等添加到列表元素上,在该元素上单击可编辑/删除项目。 So passing down a function from GrandParent and adding a parameter in Parent seems like a common enough pattern for our ConfirmationBox. 因此,从GrandParent传递一个函数并在Parent中添加一个参数对于我们的ConfirmationBox来说似乎是一个足够常见的模式。

Where then lies the problem? 那么问题出在哪里呢?

As I spoke the GrandParent is a Container that does ajax calls and keeps state. 正如我所说的,GrandParent是一个执行ajax调用并保持状态的容器。 Therefore the situation inside GrandParent might look much less like 因此,GrandParent内部的情况可能看起来不太像

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

and much more something like that 还有更多类似的东西

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

So now I cannot find a good combination from the myriad of different ways you can pass down the functions. 因此,现在我无法从传递功能的多种不同方式中找到良好的组合。

If I go with the previously shown method of <Parent deleteFunction={this.deletePerson}/> inside GrandParent and <ConfirmationBox okFunction={()=>this.props.deleteFunction(id)} /> inside Parent. 如果我使用之前显示的<Parent deleteFunction={this.deletePerson}/><Parent deleteFunction={this.deletePerson}/>方法和<Parent deleteFunction={this.deletePerson}/> <ConfirmationBox okFunction={()=>this.props.deleteFunction(id)} /> I will forward the function and be able to add parameter but the context of this. 我将转发该函数并能够添加参数,但是要添加上下文 for updateState is lost. 对于updateState丢失。 So the button-click inside modal will not refresh the state of GrandParent. 因此,在模式内部的按钮单击不会刷新GrandParent的状态。

Of the myriad of combinations of different methods of passing functions and function calls inside my three components, (using raw functions, binding the functions in render, binding them inside constructor,using arrow functions.) I did not find a workable combination that would serve the purpose of passing down a function from the GrandParent so that it could be called by clicking button inside ConfirmationBox while at the same time adding a parameter to it inside the Parent component. 在我的三个组件内部传递函数和函数调用的不同方法的众多组合中,(使用原始函数,将功能绑定到渲染器中,将其绑定到构造函数中,使用箭头函数),我找不到一种可行的组合目的是从GrandParent传递函数,以便可以通过单击ConfirmationBox中的按钮来调用它,同时在Parent组件中向其中添加参数。 Either I lose the context needed to update the state of GrandParent, or I will be unable to give a parameter, or the functions will be called on render or other such inappropriate time, or not called when needed. 我失去了更新GrandParent状态所需的上下文,或者我将无法提供参数,或者将在渲染或其他不适当的时间调用这些函数,或者在需要时不调用这些函数。 Whatever combinations I can think of something is always out of order. 我能想到的任何组合总是乱序。

I know this is piece here is rather TLDR but I wanted to add all the info I have on the problem. 我知道这是TLDR,但我想添加有关该问题的所有信息。 If someone has made it thus far and is experienced in JS/React then I am most thankful to hear your ideas how passing down functions(and or function calls) should be implemented for this to actually work out. 如果到目前为止已经有人并且在JS / React方面有丰富经验,那么我很高兴听到您的想法,应该如何实现向下传递函数(和/或函数调用)以使其真正实现。

I recently implemented something similar for a modal. 我最近为模态实现了类似的东西。 For me, the key was binding the this context in the component where it is needed. 对我来说,关键是this上下文绑定到需要它的组件中。

So in GrandParent , you set up a constructor: 因此,在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
 }
 ...

Then, deleteFunction has access to the local state of GrandParent . 然后,deleteFunction访问的本地状态GrandParent

If you pass it directly from Grandparent to Parent to Child, this should work: 如果您直接将其从“祖父母”传递给“父母到孩子”,则此方法应该有效:

In Grandparent: <Parent deleteFunction={this.deleteFunction} /> 在祖父母中: <Parent deleteFunction={this.deleteFunction} />

In Parent: <Child deleteFunction={this.props.deleteFunction} /> 在父级中: <Child deleteFunction={this.props.deleteFunction} />

In child: onClick={() => this.props.deleteFunction()} 在子级中: onClick={() => this.props.deleteFunction()}

Now, you talked about adding a parameter to the deleteFunction in Parent. 现在,您讨论了将参数添加到Parent中的deleteFunction的问题。 I would go about this by also passing the parameter from Parent to Child and then calling the function with the parameter in Child: 通过将参数从Parent传递给Child,然后使用Child中的参数调用函数,我可以解决这个问题:

In Parent: <Child deleteFunction={this.props.deleteFunction} deleteParam={param}/> 在父级中: <Child deleteFunction={this.props.deleteFunction} deleteParam={param}/>

In child: onClick={() => this.props.deleteFunction(this.props.deleteParam)} 在子级中: onClick={() => this.props.deleteFunction(this.props.deleteParam)}

Can you check what i do here and tell me if it helps you ? 您能检查一下我在这里做什么然后告诉我是否有帮助?

I'm still learning react and find your issue interesting 我仍在学习反应,发现您的问题很有趣

Jwu JWU

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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