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>
        );
    }
}
Dangling_pointer
źródło
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ść.

Davin Tryon
źródło
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 [...]

Fabien Sa
źródło
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>
Tao Wang
źródło
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);
};
Ignacy Andrzej
źródło
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>
        );
    }
}
Gabo Ruiz
źródło
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 ...

Jaroslav Benc
źródło
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.

Indygowiec
źródło
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>
    );
Shahrukh Anwar
źródło
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++ }); }

hardik chugh
źródło
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

Mselmi Ali
źródło
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>
        );
      }
    }
Neel Patel
źródło
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ę.

Prashant Yalatwar
źródło
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++
      });
   }
Emeka Augustine
źródło
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() {
   //....
   }
}
Kai
źródło
0
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Hello World</title>

    <script src="https://unpkg.com/[email protected]/dist/react.min.js"></script>
    <script src="https://unpkg.com/[email protected]/dist/react-dom.min.js"></script>
    <script src="https://unpkg.com/[email protected]/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>
Ajay Kumar
źródło
0

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

Kilo Jeden
źródło
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)
        }

K23raj
źródło
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
  }
Asgar Ali Khachay
źródło