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 คุณสามารถใช้ฟังก์ชั่นลูกศรสำหรับการประกาศฟังก์ชันเพื่อแก้ไขปัญหานี้ได้
Tal

นี่ควรเป็นคำตอบที่ถูกต้อง
Jordec

ฉันเปลี่ยนฟังก์ชั่นการตอบสนองของฉันเป็น ES6 และ Hurrey การทำงานของมัน
Ashwani Garg

คำตอบ:


448

นี่คือสาเหตุที่ไม่ได้ถูกผูกไว้กับthis.deltathis

เพื่อผูกชุดthis.delta = this.delta.bind(this)ในตัวสร้าง:

constructor(props) {
    super(props);

    this.state = {
        count : 1
    };

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

ขณะนี้คุณกำลังโทรเข้าเล่ม แต่การผูกส่งคืนฟังก์ชันที่ถูกผูกไว้ คุณต้องตั้งค่าฟังก์ชั่นเป็นค่าที่ถูกผูกไว้


186
อะไรคือสิ่งที่อยู่ในชั้นเรียน ES6 ถ้าวิธีการของพวกเขาไม่มีการthisเชื่อมคำศัพท์ที่เหมาะสมและจากนั้นไม่เปิดเผยไวยากรณ์สำหรับการเชื่อมโยงบริบทของพวกเขาโดยตรงในคำจำกัดความของพวกเขา!
AgmLauncher

1
ฉันเข้าใจประเด็นของคุณ แต่ถ้าฉันเขียนรหัสใน componentWillMount () แล้วฉันจะผูก
pareek อย่างไร

1
@sureshpareek เมื่อคุณผูกฟังก์ชั่นของคุณในนวกรรมิกมันควรจะถูกผูกไว้เมื่อคุณเรียกมันจากเบ็ดวงจรชีวิตใด ๆ
ลีวายส์ฟูลเลอร์

4
มาจาก android / java world ฉันงุนงง
ทิวดอร์

3
@AgmLauncher การใช้งานของฟังก์ชั่นแลมบ์ดาผูกนี้โดยปริยาย หากคุณกำหนดdeltaเป็นdelta = () => { return this.setState({ count: this.state.count++ }); };รหัสจะใช้งานได้ อธิบายที่นี่: hackernoon.com/…
K. Rhoda

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 doc:

จนกว่าจะถึงฟังก์ชั่นลูกศรทุกฟังก์ชั่นใหม่ที่กำหนดไว้ของตัวเองนี้ค่า [ ... ] สิ่งนี้พิสูจน์แล้วว่าน่ารำคาญด้วยรูปแบบการเขียนโปรแกรมเชิงวัตถุ

ลูกศรฟังก์ชั่นการจับภาพนี้ค่าของบริบทการปิดล้อม [ ... ]


3
บทความที่ดีอธิบายรายละเอียดนี้: reactkungfu.com/2015/07/…
Edo

อะไรคือข้อดีของการใช้อย่างใดอย่างหนึ่งนอกเหนือจากไวยากรณ์?
Jeremy D

2
ไวยากรณ์ของการโยงนั้นสะอาดกว่าเนื่องจากคุณสามารถรักษาขอบเขตปกติของวิธีการของคุณ
Fabien Sa

ไวยากรณ์ของการโยงไม่ใช่ส่วนหนึ่งของ ES2016 หรือ ES2017
Felix Kling

2
@stackoverflow ควรเพิ่มความสามารถในการเพิ่มค่าหัวให้กับคำตอบใด ๆ
Gabe

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/… .
Fabien Sa

24

เมื่อใช้รหัส ES6 ในการตอบสนองมักจะใช้ฟังก์ชั่นลูกศรเพราะบริบทนี้จะถูกผูกไว้กับมันโดยอัตโนมัติ

ใช้สิ่งนี้:

(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 ไม่สามารถทำงานร่วมกับ react และ 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
Gabo Ruiz

1
ตั้งแต่ 2019 นี่เป็นวิธีที่จะไป (Y)
MH

6

คุณยังสามารถใช้:

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

หรือ:

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

หากคุณผ่านพารามิเตอร์บางอย่าง ..


มันเป็นเรื่องที่ดีที่จะฟังก์ชั่นการใช้ลูกศรใน JSX
เกบ

5

คุณต้องผูกสิ่งนี้กับตัวสร้างและจำไว้ว่าการเปลี่ยนแปลงตัวสร้างต้องเริ่มต้นเซิร์ฟเวอร์ใหม่ มิฉะนั้นคุณจะจบลงด้วยข้อผิดพลาดเดียวกัน


1
ดึงผมออกเพราะไม่รีสตาร์ทเซิร์ฟเวอร์
kurtcorbett

5

คุณต้องผูกเมธอดของคุณด้วย 'this' (วัตถุเริ่มต้น) ดังนั้นสิ่งที่ฟังก์ชั่นของคุณอาจผูกไว้กับตัวสร้าง

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ดังนั้นตามเอกสาร js ของ Reactคุณต้องใช้วิธีการเชื่อมโยง

    บางอย่างเช่นนี้สำหรับตัวอย่างข้างต้น:

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

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับฟังก์ชั่นลูกศร:

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
  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
  }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.