React - unsaught TypeError: Không thể đọc thuộc tính 'setState' không xác định


316

Tôi nhận được lỗi sau

Uncaught TypeError: Không thể đọc thuộc tính 'setState' không xác định

thậm chí sau khi ràng buộc delta trong hàm tạo.

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
Trong ES6, bạn có thể sử dụng chức năng mũi tên để khai báo hàm để khắc phục sự cố này.
Tal

^ đây phải là câu trả lời đúng
Jordec

Tôi đã thay đổi chức năng phản hồi của mình thành ES6 và Hurrey hoạt động.
Ashwani Garg

Câu trả lời:


448

Điều này là do this.deltakhông bị ràng buộc this.

Để liên kết được thiết lập this.delta = this.delta.bind(this)trong hàm tạo:

constructor(props) {
    super(props);

    this.state = {
        count : 1
    };

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

Hiện tại, bạn đang gọi ràng buộc. Nhưng liên kết trả về một hàm ràng buộc. Bạn cần đặt hàm thành giá trị ràng buộc của nó.


187
Điều gì trên trái đất là điểm của các lớp ES6 nếu các phương thức của chúng không có thisràng buộc từ vựng phù hợp , và sau đó thậm chí không để lộ một cú pháp để ràng buộc bối cảnh của chúng trực tiếp trên định nghĩa của chúng!?
AgmLauncher

1
tôi hiểu quan điểm của bạn nhưng nếu tôi viết mã trong thành
phầnWillMount

1
@sureshpareek Khi bạn liên kết chức năng của mình trong hàm tạo, nó sẽ bị ràng buộc khi bạn gọi nó từ bất kỳ móc vòng đời nào.
Levi Fuller

4
Đến từ thế giới android / java tôi gặp khó khăn
Tudor

3
@AgmLauncher sử dụng các hàm Lambda hoàn toàn ràng buộc điều này. Nếu bạn xác định deltadelta = () => { return this.setState({ count: this.state.count++ }); };mã cũng sẽ làm việc. Giải thích tại đây: hackernoon.com/ từ
K. Rhoda

144

Trong ES7 + (ES2016), bạn có thể sử dụng toán tử cú pháp liên kết hàm thử nghiệm ::để liên kết. Nó là một loại đường cú pháp và sẽ làm giống như câu trả lời của Davin Tryon.

Sau đó bạn có thể viết lại this.delta = this.delta.bind(this);thànhthis.delta = ::this.delta;


Đối với ES6 + (ES2015), bạn cũng có thể sử dụng hàm mũi tên ES6 + ( =>) để có thể sử dụng this.

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

Tại sao ? Từ tài liệu Mozilla:

Cho đến khi các hàm mũi tên, mọi hàm mới đều tự xác định giá trị này [...]. Điều này tỏ ra khó chịu với phong cách lập trình hướng đối tượng.

Các hàm mũi tên nắm bắt giá trị này của bối cảnh kèm theo [...]


3
Bài viết rất hay mô tả điều này một cách chi tiết: Reackungfu.com/2015/07/ Kẻ
Edo

Lợi thế của việc sử dụng cái này hơn cái kia, bên cạnh cú pháp là gì?
Jeremy D

2
Cú pháp liên kết sạch hơn vì bạn có thể giữ phạm vi bình thường của phương thức của mình.
Fabien Sa

Cú pháp liên kết không phải là một phần của ES2016 hoặc ES2017.
Felix Kling

2
@stackoverflow nên thêm khả năng thêm tiền thưởng vào bất kỳ câu trả lời nào.
Gabe

29

Có một sự khác biệt về bối cảnh giữa lớp ES5 và ES6. Vì vậy, sẽ có một chút khác biệt giữa các triển khai là tốt.

Đây là phiên bản 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>
            );
    }
});

và đây là phiên bản 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>
            );
    }
}

Chỉ cần cẩn thận, bên cạnh sự khác biệt cú pháp trong việc thực hiện lớp, có một sự khác biệt trong ràng buộc xử lý sự kiện.

Trong phiên bản ES5, nó

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

Trong phiên bản ES6, đó là:

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

Sử dụng các hàm mũi tên hoặc ràng buộc trong JSX là một thực tiễn tồi. stackoverflow.com/questions/36677733/ .
Fabien Sa

24

Khi sử dụng mã ES6 trong React luôn luôn sử dụng mũi tên chức năng, bởi vì này bối cảnh được tự động binded với nó

Dùng cái này:

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

thay vì:

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

2
Nếu sử dụng hàm mũi tên và biến tham số giống với biến khóa , tôi khuyên bạn nên sử dụng nó như this.setState({videos});
jayeshkv

Đây là những gì đã làm cho tôi. Tôi mới sử dụng nút và các tài liệu cho mô-đun axios không tương thích với phản ứng và setState
dabobert

20

Bạn không phải ràng buộc bất cứ điều gì, Chỉ cần sử dụng các chức năng Mũi tên như thế này:

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

đó là những gì sự khác biệt xin vui lòng tại sao đó là?
Ridha Rezzag

4
Phạm vi này với các chức năng mũi tên được kế thừa từ bối cảnh. Với các hàm thông thường, hàm này luôn đề cập đến hàm gần nhất, trong khi với các hàm mũi tên, vấn đề này được loại bỏ và bạn sẽ không cần phải viết var that = cái này nữa. @RezzagRidha
Gabo Ruiz

1
Kể từ năm 2019, đây là con đường để đi (Y)
MH

6

Bạn cũng có thể dùng:

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

Hoặc là:

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

Nếu bạn đang vượt qua một số thông số ..


Việc sử dụng các hàm mũi tên trong JSX
Gabe

5

Bạn cần liên kết điều này với hàm tạo và nhớ rằng các thay đổi đối với hàm tạo cần khởi động lại máy chủ. Hoặc nếu không, bạn sẽ kết thúc với cùng một lỗi.


1
Đã nhổ tóc vì tôi không khởi động lại máy chủ.
kurtcorbett

5

Bạn phải liên kết các phương thức của mình với 'this' (đối tượng mặc định). Vì vậy, bất cứ chức năng nào của bạn có thể chỉ là liên kết trong hàm tạo.

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

Lỗi này có thể được giải quyết bằng nhiều phương pháp khác nhau-

  • Nếu bạn đang sử dụng cú pháp ES5 , thì theo Tài liệu React js, bạn phải sử dụng phương thức liên kết .

    Một cái gì đó như thế này cho ví dụ trên:

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

  • Nếu bạn đang sử dụng cú pháp ES6 , thì bạn không cần sử dụng phương thức liên kết , bạn có thể làm điều đó với một cái gì đó như thế này:

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


2

Có hai giải pháp cho vấn đề này:

Giải pháp đầu tiên là thêm một hàm tạo vào thành phần của bạn và liên kết hàm của bạn như dưới đây:

constructor(props) {
        super(props);

        ...

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

Vì vậy, làm điều này:

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

Thay vì điều này:

this.delta.bind(this);

Giải pháp thứ hai là sử dụng chức năng mũi tên thay thế:

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

Trên thực tế chức năng mũi tên KHÔNG ràng buộc nó là của riêng mình this. Các hàm mũi tên bindtheo ngữ cảnh của chúng để thisthực sự đề cập đến bối cảnh ban đầu .

Để biết thêm thông tin về chức năng liên kết:

Hàm Bind Hiểu JavaScript Bind ()

Để biết thêm thông tin về chức năng mũi tên:

Javascript ES6 - Hàm mũi tên và Từ điển this


1

bạn phải liên kết sự kiện mới với từ khóa này như tôi đề cập dưới đây ...

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

Thêm

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

sẽ giải quyết vấn đề. lỗi này xuất hiện khi chúng ta cố gắng gọi hàm của lớp ES6, vì vậy chúng ta cần liên kết phương thức.


1

Chức năng mũi tên có thể làm cho cuộc sống của bạn dễ dàng hơn để tránh ràng buộc từ khóa này . Thích như vậy:

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

0

mặc dù câu hỏi này đã có một giải pháp, tôi chỉ muốn chia sẻ câu hỏi của mình để làm cho nó được xóa, hy vọng nó có thể giúp:

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

Chỉ cần thay đổi câu lệnh liên kết của bạn từ những gì bạn phải => this.delta = this.delta.bind (this);


0
  1. Kiểm tra trạng thái kiểm tra trạng thái xem bạn có tạo tài sản cụ thể hay không

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

2. Kiểm tra (cái này) nếu bạn thực hiện setState bên trong bất kỳ chức năng nào (ví dụ: handChange) kiểm tra xem hàm có liên kết với hàm này hay hàm nên là hàm mũi tên.

## 3 cách để ràng buộc điều này với chức năng dưới đây ##

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

nếu bạn đang sử dụng cú pháp ES5 thì bạn cần liên kết nó đúng cách

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

và nếu bạn đang sử dụng ES6 trở lên bạn có thể sử dụng mũi tên chức năng, sau đó bạn không cần phải sử dụng bind ()

delta = () => {
    // do something
  }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.