React - nieprzechwycony TypeError: Nie można odczytać właściwości „setState” niezdefiniowanej


316

Otrzymuję następujący błąd

Uncaught TypeError: Nie można odczytać właściwości „setState” niezdefiniowanej

nawet po powiązaniu delty w konstruktorze.

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
w ES6 można użyć funkcji strzałki do deklaracji funkcji, aby rozwiązać ten problem.
Tal

^ to powinna być poprawna odpowiedź
Jordec

Zmieniłem funkcję odpowiedzi na ES6 i hurrey, działa.
Ashwani Garg

Odpowiedzi:


448

Wynika to z this.deltabraku bycia związanym this.

Aby powiązać zestaw this.delta = this.delta.bind(this)w konstruktorze:

constructor(props) {
    super(props);

    this.state = {
        count : 1
    };

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

Obecnie nazywasz się bind. Ale bind zwraca funkcję powiązaną. Musisz ustawić funkcję na związaną wartość.


186
Jaki jest sens klas ES6, jeśli ich metody nie mają odpowiedniego thispowiązania leksykalnego , a następnie nawet nie ujawniają składni dla powiązania swojego kontekstu bezpośrednio z ich definicją !?
AgmLauncher

1
rozumiem twój punkt, ale jeśli napiszę kod w
module

1
@sureshpareek Po powiązaniu funkcji w konstruktorze należy ją związać, gdy wywołasz ją z dowolnego haka cyklu życia.
Levi Fuller,

4
Pochodzę ze świata Androida / Java. Jestem zaskoczony
Tudor

3
@AgmLauncher używa funkcji Lambda domyślnie to wiąże. Jeśli zdefiniowałeś deltajako delta = () => { return this.setState({ count: this.state.count++ }); };kod, działałoby również. Wyjaśniono tutaj: hackernoon.com/…
K. Rhoda

144

W ES7 + (ES2016) do powiązania można użyć operatora eksperymentalnej funkcji składni:: powiązania. Jest to cukier składniowy i zrobi to samo, co odpowiedź Davina Tryona.

Następnie możesz przepisać this.delta = this.delta.bind(this);nathis.delta = ::this.delta;


W przypadku ES6 + (ES2015) można również użyć funkcji strzałki ES6 + ( =>), aby móc korzystać this.

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

Dlaczego ? Z dokumentu Mozilli:

Do czasu funkcji strzałek każda nowa funkcja zdefiniowała własną wartość [...]. Okazało się to denerwujące w przypadku programowania obiektowego.

Funkcje strzałek przechwytują wartość otaczającego kontekstu [...]


3
Fajny artykuł opisujący to szczegółowo: reagkungfu.com/2015/07/…
Edo,

Jaka jest zaleta używania jednego nad drugim oprócz składni?
Jeremy D,

2
Składnia wiązania jest czystsza, ponieważ można zachować normalny zakres metody.
Fabien Sa

Składnia wiązania nie jest częścią ES2016 ani ES2017.
Felix Kling

2
@stackoverflow powinien dodać możliwość dodania nagrody do każdej odpowiedzi.
Gabe,

29

Istnieje różnica kontekstu między klasą ES5 i ES6. Tak więc będzie także niewielka różnica między implementacjami.

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

a oto wersja 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>
            );
    }
}

Bądź ostrożny, poza różnicą składniową w implementacji klasy, istnieje różnica w powiązaniu modułu obsługi zdarzeń.

W wersji ES5 jest to

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

W wersji ES6 jest to:

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

Używanie funkcji strzałek lub wiązanie w JSX jest złą praktyką. stackoverflow.com/questions/36677733/... .
Fabien Sa

24

Korzystając z kodu ES6 w React, zawsze używaj funkcji strzałek, ponieważ ten kontekst jest z nim automatycznie powiązany

Użyj tego:

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

zamiast:

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

2
Jeśli używasz funkcji strzałki, a zmienna parametru jest taka sama jak zmienna kluczowa , this.setState({videos});
zaleciłbym

To właśnie to dla mnie zrobiło. Jestem nowy w węźle, a dokumentacja modułu axios była niezgodna z reakcją i setState
dabobert

20

Nie musisz nic wiązać, po prostu użyj funkcji strzałek w następujący sposób:

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

to działa jaka jest różnica, proszę, dlaczego to jest?
Ridha Rezzag

4
Ten zakres z funkcjami strzałek jest dziedziczony z kontekstu. W przypadku zwykłych funkcji zawsze odnosi się to do najbliższej funkcji, podczas gdy w przypadku funkcji strzałek problem ten jest usuwany i nie będziesz musiał więcej pisać var ​​that = this. @RezzagRidha
Gabo Ruiz

1
Od 2019 r. Jest to najlepsza droga (Y)
MH

6

Możesz także użyć:

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

Lub:

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

Jeśli mijasz jakieś parametry ...


Złą praktyką jest używanie funkcji strzałek w JSX
Gabe,

5

Musisz powiązać to z konstruktorem i pamiętać, że zmiany w konstruktorze wymagają zrestartowania serwera. Albo skończysz z tym samym błędem.


1
Wyciągałem włosy, bo nie uruchomiłem ponownie serwera.
kurtcorbett

5

Musisz powiązać swoje metody z „tym” (obiekt domyślny). Więc cokolwiek twoja funkcja może być po prostu powiązać to w konstruktorze.

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

Ten błąd można rozwiązać różnymi metodami

  • Jeśli używasz składni ES5 , to zgodnie z dokumentacją React js musisz użyć metody bind .

    Coś takiego w powyższym przykładzie:

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

  • Jeśli używasz składni ES6 , nie musisz używać metody bind , możesz to zrobić w następujący sposób:

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


2

Istnieją dwa rozwiązania tego problemu:

Pierwszym rozwiązaniem jest dodanie konstruktora do komponentu i powiązanie funkcji w następujący sposób:

constructor(props) {
        super(props);

        ...

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

Więc zrób to:

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

Zamiast tego:

this.delta.bind(this);

Drugim rozwiązaniem jest użycie zamiast tego funkcji strzałki:

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

W rzeczywistości funkcja strzałki NIE Wiąże własnego this. Funkcje strzałek leksykalnie bindich kontekst, więc thisfaktycznie odnosi się do kontekstu źródłowego .

Aby uzyskać więcej informacji o funkcji wiązania:

Funkcja wiązania Zrozumienie JavaScript Bind ()

Aby uzyskać więcej informacji na temat funkcji strzałek:

JavaScript ES6 - Funkcje strzałek i leksykalne this


1

musisz powiązać nowe wydarzenie z tym słowem kluczowym, jak wspomniałem poniżej ...

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

Dodawanie

onClick = {this.delta.bind (this)}

rozwiąże problem. ten błąd pojawia się, gdy próbujemy wywołać funkcję klasy ES6, więc musimy powiązać metodę.


1

Funkcja strzałki może ułatwić ci życie, unikając wiązania tego słowa kluczowego. Tak jak:

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

0

choć to pytanie miało już rozwiązanie, chcę tylko udostępnić moje, aby je rozwiązać, mam nadzieję, że może pomóc:

/* 
 * 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

Po prostu zmień instrukcję bind z tego, co musisz => this.delta = this.delta.bind (this);


0
  1. Sprawdź stan sprawdź stan, czy tworzysz określoną właściwość, czy nie

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

2. Zaznacz (this), jeśli wykonujesz setState wewnątrz dowolnej funkcji (tj. HandleChange), sprawdź, czy funkcja wiąże się z tą funkcją, czy funkcja powinna być funkcją strzałki.

## 3 sposoby na powiązanie tego z poniższą funkcją ##

//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

jeśli używasz składni ES5, musisz ją odpowiednio powiązać

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

i jeśli używasz ES6 i powyżej można użyć strzałek funkcji, wtedy nie trzeba używać bind () to

delta = () => {
    // do something
  }
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.