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, і хурі, її працює.
Ашвані Гарг

Відповіді:


448

Це пов’язано з тим, що this.deltaне зобов’язаний this.

Для того, щоб прив'язати набір this.delta = this.delta.bind(this)у конструкторі:

constructor(props) {
    super(props);

    this.state = {
        count : 1
    };

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

Наразі вам дзвонять прив’язати. Але bind повертає зв'язану функцію. Потрібно встановити функцію на її обмежене значення.


186
У чому полягає суть класів ES6, якщо їхні методи не мають належного лексичного thisзв’язування, а потім навіть не розкривають синтаксис для прив'язки свого контексту безпосередньо до їх визначення !?
AgmLauncher

1
Я розумію вашу думку, але якщо я напишу код в компонентWillMount (), то як я буду прив'язувати
suresh pareek

1
@sureshpareek Після того, як ви зв’яжете свою функцію в конструкторі, вона повинна бути пов'язана, коли ви викликаєте її з будь-якого гака життєвого циклу.
Леві Фуллер

4
Приїжджаючи з андроїд / java світу я збентежений
Тюдор

3
@AgmLauncher використання функцій Lambda неявно пов'язує це. Якщо ви визначили delta, delta = () => { return this.setState({ count: this.state.count++ }); };що код також буде працювати. Пояснено
К. Рода

144

У ES7 + (ES2016) ви можете використовувати експериментальну функцію оператора зв'язування синтаксису:: для прив’язки. Це синтаксичний цукор і буде робити те саме, що відповідь Девіна Тріона.

Потім ви можете переписати this.delta = this.delta.bind(this);наthis.delta = ::this.delta;


Для ES6 + (ES2015) ви також можете використовувати функцію стрілки ES6 + ( =>), щоб мати можливість використовувати this.

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

Чому? Від документа Mozilla:

До функцій стрілок, кожна нова функція не визначила своє власне це значення [...]. Це виявило роздратування при об'єктно-орієнтованому стилі програмування.

Функції стрілки фіксують це значення контексту, що обговорюється [...]


3
Приємна стаття, яка детально описує це: reactkungfu.com/2015/07/…
Едо

Яка перевага використання одного над іншим, крім синтаксису?
Джеремі D

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
Якщо використання функції стрілки і змінна параметри збігається з ключовою змінною , я рекомендую використовувати її як this.setState({videos});
jayeshkv

Це те, що зробило це для мене. Я новачок у вузлі, і документи для модуля axios були несумісні з реагуванням та setState
dabobert

20

Вам нічого не потрібно зв’язувати, просто використовуйте такі функції стрілок:

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

що працює, яка різниця, будь ласка, чому це?
Ridha Rezzag

4
Цей діапазон із функціями стрілок успадковується з контексту. При регулярних функціях це завжди стосується найближчої функції, тоді як при функціях зі стрілками ця проблема усувається, і вам більше не потрібно буде писати var що = це. @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 , то вам не потрібно використовувати метод прив’язки , ви можете зробити це з чимось таким:

    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 (this)}

вирішить проблему. ця помилка виникає, коли ми намагаємося викликати функцію класу 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. Перевірте (це), якщо ви робите 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.