react function this correlation

In the process of using react, the execution result is not as expected because of this problem of function. Now, to sort out the following problems, first look at the code:

import React from "react";

class MsgList extends React.PureComponent {
  render() {
    return (
      <ul>
        {this.props.list.map((item, index) => (<li key={index}>{item}</li>))}
      </ul>
    )
  }
}

export default class List extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      inputMsg: '',
      list: [123]
    }
  }
  
  handleInput = (val) => {
    this.setState({
      inputMsg: val.target.value
    })
  }

  handleSubmit = () => {
    const text = this.state.inputMsg
    if (text) {
      const msg = [...this.state.list, text]
      this.setState({
        inputMsg: '',
        list: msg
      })
    }
  }

  render() {
    return (
      <div>
        <MsgList list={this.state.list}/>
        <input type="text" value={this.state.inputMsg}
            onChange={this.handleInput}/>
        <button onClick={this.handleSubmit}>Submission</button>
      </div>
    )
  }
}

The sample code implements simple element addition and list display functions.

Function binding and definition are as follows:

// binding
onChange={this.handleInput}
// Definition
handleInput = (val) => {
  this.setState({
    inputMsg: val.target.value
  })
}

There are many ways to define functions, such as:

handleInput(val) {
  console.log(val.target)
  console.log(this)
  this.setState({
    inputMsg: val.target.value
  })
}

At this time, val.target is the < input > element, but this is undefined. At this time, calling this.setState will report an error.

Class will not bind this by default, so the context of function execution is lost here. If you add a pair of parentheses when Binding:

<input type="text" value={this.state.inputMsg} onChange={this.handleInput()}/>

// Function definition
handleInput(val) {
  console.log(val.target)
  console.log(this)
  this.setState({
      inputMsg: val.target.value
  })
}

At this time, add brackets. Although the context is bound, this will cause the function to be triggered when the component renders, rather than by clicking when the rendering is finished, and the onChange action cannot be responded to. Components trigger functions in rendering process. Calling setState() in function calls render again, resulting in a dead loop.

If. bind() is used as the binding context of the function at the beginning, remove the brackets when binding the function,

constructor(props) {
  super(props)
  this.state = {
    inputMsg: 'hello',
    list: [123]
  }
  this.handleInput = this.handleInput.bind(this)
}

At this time, the function is normal.

In the beginning, we used arrow function to bind context when defining function, so we can also achieve the desired function.

In addition, there's another way of writing that works, but it's actually the same as the first one.

<input type="text" value={this.state.inputMsg} onChange={(e)=>this.handleInput(e)}/>

Summary

When using react, you should pay attention to the direction of this. By default, a class will not bind this to a method, either manually bind this at the beginning, or use the arrow function to automatically bind the context. If it is not a function that you want to trigger when the component renders, you cannot bind the function with parentheses.

Reference material

this binding

Keywords: Javascript React

Added by billman on Sun, 08 Dec 2019 09:39:13 +0200