Как исправить ошибку — this.setState не является функцией в React

Если вы новичок в react и используете компоненты на основе классов, вы могли видеть в браузере следующие ошибки:

TypeError: Cannot read properties of undefined (reading 'setState')

TypeError: this.setState is not a function

Задумывались ли вы, почему возникает эта ошибка и как ее исправить? В этой статье мы расскажем об этом.

Воспроизведение ошибки

Рассмотрим следующий код:

import React, { Component } from "react"
import "./App.css"

export default class App extends Component {
  constructor(props) {
    super(props)

    this.state = { counter: 0 }
  }

  updateCounter() {
    this.setState({ counter: this.state.counter + 1 })
  }

  render() {
    return (
      <div className="App">
        <button onClick={this.updateCounter}>
          Clicked {this.state.counter} Times
        </button>
      </div>
    )
  }
}
Вход в полноэкранный режим Выйти из полноэкранного режима

Когда вы быстро просмотрите код, вам покажется, что он в полном порядке. Однако если вы запустите код и нажмете на кнопку, ничего не произойдет. Если вы проверите консоль браузера, то увидите следующую ошибку:

Причина ошибки

Причина возникновения этой ошибки кроется в концепции, называемой Closures в JavaScript. Это означает, что область видимости/контекст функции updateCounter и класса App не совпадают.
Это означает, что App и updateCounter имеют разные this.

В нашем случае мы пытаемся получить доступ к this класса App из функции, которая имеет свой собственный this, который в настоящее время undefined. Отсюда ошибка Cannot read properties of undefined.

Как исправить ошибку

Есть 2 способа исправить эту проблему:

Использование стрелочных функций ES6

Самый простой способ исправить проблему — преобразовать функцию updateCounter в стрелочную функцию, как показано ниже:

import React, { Component } from "react"
import "./App.css"

export default class App extends Component {
  constructor(props) {
    super(props)

    this.state = { counter: 0 }
  }

  updateCounter = () => {
    this.setState({ counter: this.state.counter + 1 })
  }

  render() {
    return (
      <div className="App">
        <button onClick={this.updateCounter}>
          Clicked {this.state.counter} Times
        </button>
      </div>
    )
  }
}
Вход в полноэкранный режим Выход из полноэкранного режима

Если вы протестируете приложение сейчас, вы увидите, что счетчик обновляется при нажатии на кнопку.

Вы можете спросить, как замена функции на функцию со стрелкой неожиданно устранила проблему? Что случилось с this, которая была undefined? Ну, стрелочные функции не имеют собственных this! Они ссылаются на this лексической среды/контекста, внутри которого они объявлены.

В нашем случае, функция updateCounter определена внутри класса App, и она ссылается на this класса, следовательно, this.setState работает!

Привязка к функции

Что если вы не хотите использовать стрелочную функцию (ну я не вижу причин, почему вы не должны этого делать!) и исправить код с помощью традиционной функции? Ну, есть способ!

Мы можем связать this из класса App, чтобы

import React, { Component } from "react"
import "./App.css"

export default class App extends Component {
  constructor(props) {
    super(props)

    this.state = { counter: 0 }

    this.updateCounter = this.updateCounter.bind(this)
  }

  updateCounter() {
    this.setState({ counter: this.state.counter + 1 })
  }

  render() {
    return (
      <div className="App">
        <button onClick={this.updateCounter}>
          Clicked {this.state.counter} Times
        </button>
      </div>
    )
  }
}
Вход в полноэкранный режим Выйти из полноэкранного режима

Синтаксис может выглядеть странно, но все, что он делает, это привязывает this класса к функции.

Подобные проблемы не возникнут при использовании функциональных компонентов с крючками, поскольку они не используют this.

Оцените статью
devanswers.ru
Добавить комментарий