简体   繁体   中英

How to call handler function from a child of a child component (ReactJS)

I'm wondering what is the best way of doing this.

I have 3 components, App, String and Note. Before I was creating Note elements in App like this:

<Note
          state={this.state.btnStates[i]}
          onClick={() => this.handleClick(i)}
        /> 

and it was working like charm (handleClick is of course in the most parent component - App)

but now I want to transfer note creation to the String component, I thought that would be easy but what I thought to work just doesn't. I'm doing it like this: in App component i render String:

          <String
            btnStates={this.state.btnStates}
            onClick={(i) => this.handleClick(i)}
          ></String>

in String component:

    for (var i = 0; i < stringLength; i++) {
      notes.push(
        <Note
          key={i}
          onClick={keyFromNoteCall => this.props.onClick(keyFromNoteCall)}
          state={this.props.btnStates[i]}
        ></Note>
      );
    }

and in Note component:

      <input
        type="button"
        className={this.getClassName(this.props.state)}
        onClick={() => this.props.onClick(this.props.key)}
        value={this.props.value}
        disabled={this.isDisabled()}
      />

What is the React way of doing such things? I need the logic to be handled in the App, but I would like move the rendering of Notes in a loop to another component.

*UPDATE: it turned out the problem was "key" property as it can't be accessed with {this.props.key} I created another property "id" for that purpose and it works. I have another problem now, that even after binding in App constructor, this logged in handleClick function doesn't show App component but rather the Note itself :/

Without using a state handler like Context or Redux, the React way of doing it is passing the function as props.

App.js

<String
    btnStates={this.state.btnStates}
    handleClick={this.handleClick}
/> 

String component

for (var i = 0; i < stringLength; i++) {
      notes.push(
        <Note
          key={i}
          handleClick={this.props.handleClick}
          state={this.props.btnStates[i]}
        ></Note>
      );
    }

Note component

<input
    type="button"
    className={this.getClassName(this.props.state)}
    onClick={() => this.props.handleClick(this.props.key)}
    value={this.props.value}
    disabled={this.isDisabled()}
  />

Also I recommend you that in your String component you do a .map() instead of a for loop.

notes.map(note => 
    <Note key={note.id} 
    handleClick={this.props.handleClick}
    state={note.btnStates}
)

This way you would have to refactor to have IDs on your notes but you should do it because using indexes as keys can cause problems.

If I understood you correctly, you should change onClick in App to this and that should do it.

<String
    btnStates={this.state.btnStates}
    onClick={this.handleClick}
/>

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