React - uncaught TypeError: Невозможно прочитать свойство 'setState' из неопределенного


316

Я получаю следующую ошибку

Uncaught TypeError: Невозможно прочитать свойство 'setState' из неопределенного

даже после связывания дельты в конструкторе.

class Counter extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            count : 1
        };

        this.delta.bind(this);
    }

    delta() {
        this.setState({
            count : this.state.count++
        });
    }

    render() {
        return (
            <div>
                <h1>{this.state.count}</h1>
                <button onClick={this.delta}>+</button>
            </div>
        );
    }
}

4
в ES6, вы можете использовать функцию стрелки для объявления функции, чтобы решить эту проблему.
Тал

^ это должен быть правильный ответ
Джордек

Я изменил свою функцию ответа на ES6, и ура, она работает.
Ашвани Гарг

Ответы:


449

Это связано с тем, что вы this.deltaне связаны с this.

Чтобы связать набор this.delta = this.delta.bind(this)в конструкторе:

constructor(props) {
    super(props);

    this.state = {
        count : 1
    };

    this.delta = this.delta.bind(this);
}

В настоящее время вы звоните связать. Но связывание возвращает связанную функцию. Вам нужно установить функцию в ее связанное значение.


188
Какой смысл в классах ES6, если их методы не имеют надлежащей лексической thisпривязки, а затем даже не предоставляют синтаксис для привязки их контекста непосредственно к их определению !?
AgmLauncher

1
Я понимаю вашу точку зрения, но если я напишу код в componentWillMount (), то как я буду связываться
Суреш Пайрик

1
@sureshpareek Когда вы связываете свою функцию в конструкторе, она должна быть связана, когда вы вызываете ее из любого хука жизненного цикла.
Леви Фуллер

4
Исходя из мира Android / Java я сбит с толку
Tudor

3
@AgmLauncher использование лямбда-функций неявно связывает это. Если вы определили deltaкак delta = () => { return this.setState({ count: this.state.count++ }); };код, также будет работать. Объясняется здесь: hackernoon.com/…
К. Рода

145

В ES7 + (ES2016) вы можете использовать экспериментальный оператор синтаксиса:: bind для привязки. Это синтаксический сахар, и он сделает то же самое, что и ответ Дэвина Трайона.

Вы можете переписать this.delta = this.delta.bind(this);вthis.delta = ::this.delta;


Для ES6 + (ES2015) вы также можете использовать функцию стрелки ES6 + ( =>) для возможности использования this.

delta = () => {
    this.setState({
        count : this.state.count + 1
    });
}

Зачем ? Из документа Mozilla:

До функций стрелок, каждая новая функция не определила свое собственное это значение [...]. Это оказалось раздражающим с объектно-ориентированным стилем программирования.

Функции со стрелками фиксируют значение this окружающего контекста [...]


3
Хорошая статья, описывающая это в деталях: reactkungfu.com/2015/07/…
Эдо

В чем преимущество использования одного над другим, кроме синтаксиса?
Джереми Д

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

Синтаксис привязки не является частью ES2016 или ES2017.
Феликс Клинг

2
@stackoverflow должен добавить возможность добавлять вознаграждение к любому ответу.
Гейб

29

Существует разница контекста между классами ES5 и ES6. Таким образом, между реализациями также будет небольшая разница.

Вот версия ES5:

var Counter = React.createClass({
    getInitialState: function() { return { count : 1 }; },
    delta: function() {
        this.setState({
            count : this.state.count++
        });
    },
    render: function() {
        return (
            <div>
              <h1>{this.state.count}</h1>
              <button onClick={this.delta}>+</button>
            </div>
            );
    }
});

и вот версия ES6:

class Counter extends React.Component {
    constructor(props) {
        super(props);
        this.state = { count : 1 };
    }

    delta() {
        this.setState({
            count : this.state.count++
        });
    }

    render() {
        return (
            <div>
              <h1>{this.state.count}</h1>
              <button onClick={this.delta.bind(this)}>+</button>
            </div>
            );
    }
}

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

В версии ES5 это

              <button onClick={this.delta}>+</button>

В версии ES6 это:

              <button onClick={this.delta.bind(this)}>+</button>

Использование функций стрелок или связывания в JSX - плохая практика. stackoverflow.com/questions/36677733/… .
Фабьен Са

24

При использовании кода ES6 в React всегда используйте функции стрелок, потому что этот контекст автоматически связывается с ним

Использовать это:

(videos) => {
    this.setState({ videos: videos });
    console.log(this.state.videos);
};

вместо того:

function(videos) {
    this.setState({ videos: videos });
    console.log(this.state.videos);
};

2
Если использовать функцию стрелки и переменную параметра так же, как переменную key , я бы порекомендовал использовать ее как this.setState({videos});
jayeshkv

Это то, что сделал это для меня. Я новичок в узле, и документы для модуля axios были несовместимы с реагировать и setState
dabobert

20

Вам не нужно ничего связывать, просто используйте функции Arrow следующим образом:

class Counter extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            count: 1
        };

    }
    //ARROW FUNCTION
    delta = () => {
        this.setState({
            count: this.state.count++
        });
    }

    render() {
        return (
            <div>
                <h1>{this.state.count}</h1>
                <button onClick={this.delta}>+</button>
            </div>
        );
    }
}

это работает, какая разница, пожалуйста, почему это?
Риджа Реззаг

4
Область действия this с функциями стрелок наследуется от контекста. Для обычных функций это всегда относится к ближайшей функции, в то время как для функций со стрелками эта проблема устранена, и вам не нужно будет писать var that = this снова. @RezzagRidha
Габо Руис

1
По состоянию на 2019 год это путь (Y)
MH

6

Вы также можете использовать:

<button onClick={()=>this.delta()}>+</button>

Или:

<button onClick={event=>this.delta(event)}>+</button>

Если вы передаете некоторые параметры ..


Это плохая практика - использовать функции стрелок в JSX
Gabe

5

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


1
Вытаскивал мои волосы, потому что я не перезагружал сервер.
kurtcorbett

5

Вы должны связать свои методы с этим (объект по умолчанию). Так что, какой бы ни была ваша функция, просто свяжите это в конструкторе.

constructor(props) {
    super(props);
    this.state = { checked:false };

    this.handleChecked = this.handleChecked.bind(this);
}

handleChecked(){
    this.setState({
        checked: !(this.state.checked)
    })
}

render(){
    var msg;

    if(this.state.checked){
        msg = 'checked'
    }
    else{
        msg = 'not checked'
    }

    return (
        <div>               
            <input type='checkbox' defaultChecked = {this.state.checked} onChange = {this.handleChecked} />
            <h3>This is {msg}</h3>
        </div>
    );

4

Эта ошибка может быть решена различными способами:

  • Если вы используете синтаксис ES5 , то в соответствии с документацией React JS вы должны использовать метод связывания .

    Примерно так для приведенного выше примера:

    this.delta = this.delta.bind(this)

  • Если вы используете синтаксис ES6 , вам не нужно использовать метод bind , вы можете сделать это примерно так:

    delta=()=>{ this.setState({ count : this.state.count++ }); }


2

Есть два решения этой проблемы:

Первое решение - добавить конструктор к вашему компоненту и связать вашу функцию, как показано ниже:

constructor(props) {
        super(props);

        ...

        this.delta = this.delta.bind(this);
    }

Так что сделайте это:

this.delta = this.delta.bind(this); 

Вместо этого:

this.delta.bind(this);

Второе решение - использовать функцию стрелки вместо:

delta = () => {
       this.setState({
           count : this.state.count++
      });
   }

На самом деле функция стрелки НЕ связывает свою собственную this. Стрелка Функции лексически bindих контекст, так что thisфактически ссылается на исходный контекст .

Для получения дополнительной информации о функции связывания:

Функция привязки Понимание JavaScript Bind ()

Для получения дополнительной информации о функции стрелки:

Javascript ES6 - функции стрелок и лексические this


1

Вы должны связать новое событие с этим ключевым словом, как я упоминаю ниже ...

class Counter extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            count : 1
        };

        this.delta = this.delta.bind(this);
    }

    delta() {
        this.setState({
            count : this.state.count++
        });
    }

    render() {
        return (
            <div>
                <h1>{this.state.count}</h1>
                <button onClick={this.delta}>+</button>
            </div>
        );
      }
    }

1

Добавление

OnClick = {this.delta.bind (это)}

решит проблему. эта ошибка возникает, когда мы пытаемся вызвать функцию класса ES6, поэтому нам нужно привязать метод.


1

Функция стрелки могла бы сделать вашу жизнь проще, чтобы избежать связывания этого ключевого слова. Вот так:

 delta = () => {
       this.setState({
           count : this.state.count++
      });
   }

0

хотя у этого вопроса уже есть решение, я просто хочу поделиться своим, чтобы прояснить его, надеюсь, это поможет:

/* 
 * The root cause is method doesn't in the App's context 
 * so that it can't access other attributes of "this".
 * Below are few ways to define App's method property
 */
class App extends React.Component {
  constructor() {
     this.sayHi = 'hello';
     // create method inside constructor, context = this
     this.method = ()=> {  console.log(this.sayHi) };

     // bind method1 in constructor into context 'this'
     this.method1 = this.method.bind(this)
  }

  // method1 was defined here
  method1() {
      console.log(this.sayHi);
  }

  // create method property by arrow function. I recommend this.
  method2 = () => {
      console.log(this.sayHi);
  }
   render() {
   //....
   }
}

0
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Hello World</title>

    <script src="https://unpkg.com/react@0.14.8/dist/react.min.js"></script>
    <script src="https://unpkg.com/react-dom@0.14.8/dist/react-dom.min.js"></script>
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>

  </head>
  <body>
  <div id="root"></div>
    <script type="text/babel">

        class App extends React.Component{

            constructor(props){
                super(props);
                this.state = {
                    counter : 0,
                    isToggle: false
                }
            this.onEventHandler = this.onEventHandler.bind(this);   
            }

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

            decrement= ()=>{
                if(this.state.counter > 0 ){
                this.setState({counter:this.state.counter - 1});    
                }else{
                this.setState({counter:0});             
                }
            }
            // Either do it as onEventHandler = () => {} with binding with this  // object. 
            onEventHandler(){
                this.setState({isToggle:!this.state.isToggle})
                alert('Hello');
            }


            render(){
                return(
                    <div>
                        <button onClick={this.increment}> Increment </button>
                        <button onClick={this.decrement}> Decrement </button>
                        {this.state.counter}
                        <button onClick={this.onEventHandler}> {this.state.isToggle ? 'Hi':'Ajay'} </button>

                    </div>
                    )
            }
        }
        ReactDOM.render(
        <App/>,
        document.getElementById('root'),
      );
    </script>
  </body>
  </html>

0

Просто измените свое заявление на связывание с того, что вы должны => this.delta = this.delta.bind (this);


0
  1. Проверьте состояние, проверьте состояние, создаете ли вы конкретное свойство или нет

this.state = {
            name: "",
            email: ""
            }
            
           
            
this.setState(() => ({ 
             comments: comments          //comments not available in state
             })) 

2. Проверьте (this), если вы выполняете setState внутри какой-либо функции (например, handleChange), проверьте, должна ли функция связываться с этим или функция должна быть функцией стрелки.

## 3 способа связать это с функцией ниже ##

//3 ways for binding this to the below function

handleNameChange(e) {  
     this.setState(() => ({ name }))
    }
    
// 1.Bind while callling function
      onChange={this.handleNameChange.bind(this)}
      
      
//2.make it as arrow function
     handleNameChange((e)=> {  
     this.setState(() => ({ name }))
     })
    
//3.Bind in constuctor 

constructor(props) {
        super(props)
        this.state = {
            name: "",
            email: ""
        }
        this.handleNameChange = this.handleNameChange.bind(this)
        }


0

если вы используете синтаксис ES5, то вам нужно правильно связать его

this.delta = this.delta.bind(this)

и если вы используете ES6 и выше , вы можете использовать стрелки функцию, то вам не нужно использовать привязки () это

delta = () => {
    // do something
  }
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.