ReactJS: setTimeout () ไม่ทำงาน?


104

มีรหัสนี้อยู่ในใจ:

var Component = React.createClass({

    getInitialState: function () {
        return {position: 0};    
    },

    componentDidMount: function () {
        setTimeout(this.setState({position: 1}), 3000);
    },

    render: function () {
         return (
            <div className="component">
                {this.state.position}
            </div>
         ); 
    }

});

ReactDOM.render(
    <Component />,
    document.getElementById('main')
);

สถานะไม่ควรเปลี่ยนหลังจาก 3 วินาทีเท่านั้นหรือ? มันเปลี่ยนทันที

เป้าหมายหลักของฉันที่นี่คือการเปลี่ยนสถานะทุกๆ 3 วินาที (ด้วยsetInterval()) แต่เนื่องจากมันไม่ทำงานฉันจึงพยายามsetTimeout()ซึ่งก็ไม่ได้ผลเช่นกัน มีไฟอะไรไหม ขอบคุณ!


2
ถ้าคุณได้foo(bar())แล้วbarมีการดำเนินการครั้งแรกfooและค่าตอบแทนของมันจะถูกส่งผ่านไปยัง
Felix Kling

@FelixKling ที่ดูเหมือนถูกต้อง แต่ไม่เหมาะสม เนื่องจากfoo()นี่คือการดำเนินการbarหลังจากหมดเวลาที่ต้องการ หรือว่าฉันผิดทั้งหมดและดำเนินการทันทีและคืนค่าหลังจากเวลาที่ต้องการเท่านั้น?
jbarradas

3
"เนื่องจาก foo () ที่นี่คือการเรียกใช้แถบหลังจากหมดเวลาที่ต้องการ" ถูกต้องนั่นคือเหตุผลที่คุณต้องผ่านbarไม่ใช่เรียกมันและส่งคืนมูลค่าของมัน คุณคาดหวังว่าพฤติกรรมfoo(bar())จะเปลี่ยนไปขึ้นอยู่กับสิ่งที่fooกำลังทำอยู่หรือไม่? นั่นจะเป็นเรื่องแปลกจริงๆ
Felix Kling

คำตอบ:


246

ทำ

setTimeout(
    function() {
        this.setState({ position: 1 });
    }
    .bind(this),
    3000
);

มิฉะนั้นคุณจะผ่านผลมาจากการsetStatesetTimeout

คุณยังสามารถใช้ฟังก์ชันลูกศร ES6 เพื่อหลีกเลี่ยงการใช้thisคำสำคัญ:

setTimeout(
  () => this.setState({ position: 1 }), 
  3000
);

1
ใช่เข้าท่าและใช้งานได้จริง แต่ไม่ใช่ function () ฟังก์ชัน? แล้วทำไมเราต้องผูกมัน? ฉันลองแล้วและมันจำเป็นจริงๆฉันแค่อยากรู้ว่าทำไม ขอบคุณสำหรับความช่วยเหลือของคุณ :)
jbarradas

ฉันไม่เข้าใจว่าทำไมคุณถึงบอกว่ามันจะส่งผลลัพธ์ไปยัง setTimeout มันจะไม่ทำให้มันทำงานได้อย่างไร พฤติกรรมในกรณีนั้นคืออะไร?
PositiveGuy

16
สำหรับผู้ที่ต้องการใช้ฟังก์ชันลูกศร ES6: setTimeout(() => {this.setState({ position: 1 })}, 3000)@PositiveGuy ไม่แน่ใจว่าคุณได้ค้นคว้าสิ่งนี้ด้วยตัวเองหรือไม่เนื่องจากคำถามนี้ถูกโพสต์ แต่ในกรณีที่คุณไม่ได้: ตัวอย่างดั้งเดิมของ Daniel จำเป็นต้อง.bind(this)จำกัดthisบริบทเป็นsetStateอย่างอื่น , thisโดยอัตโนมัติจะอ้างถึงบริบทในการที่จะมีการเรียกใช้ (ในกรณีนี้ที่ไม่ระบุชื่อfunctionที่ถูกส่งผ่านไปsetTimeout) อย่างไรก็ตามฟังก์ชันลูกศร ES6 มีการกำหนดขอบเขตคำศัพท์ - จำกัด เฉพาะthisบริบทที่เรียกใช้
Zac Collier

1
ไม่ทำงาน ... setTimeout (() => {if (! this.props.logoIsLoading &&! this.props.isLoading) {console.log ('เราจะเกิดขึ้นไหม'); this.setState ({.. .this.state, shouldUpdate: false, itemToUpdate: null, modalIsOpen: false, modalTitle: 'Add New Organization'});}}, 100); ในบริบทของคลาส syntactical น้ำตาลระดับองค์กรขยาย Component {console.log ไม่เคยได้รับ console.log ('เราจะเกิดขึ้นหรือไม่'); ทุกอย่างก่อนและหลังเข้าสู่ระบบ
juslintek

@juslintek กำหนดไม่ทำงาน โปรดถามคำถามใหม่หากจำเป็น
Daniel

151
setTimeout(() => {
  this.setState({ position: 1 });
}, 3000);

ข้างต้นจะใช้งานได้เนื่องจากฟังก์ชันลูกศร ES6 ไม่เปลี่ยนบริบทของthis.


3
ไวยากรณ์ ES6 ควรเป็นคำตอบที่ยอมรับสำหรับแนวทางปฏิบัติที่ดีที่สุดใน React ทั้งสองจะทำงาน thisแต่นี้เป็นสง่างามมากขึ้นและมือจับ
mccambridge

24

เมื่อใดก็ตามที่เราสร้างการหมดเวลาเราควรล้างมันบน componentWillUnmount หากยังไม่เริ่มทำงาน

      let myVar;
         const Component = React.createClass({

            getInitialState: function () {
                return {position: 0};    
            },

            componentDidMount: function () {
                 myVar = setTimeout(()=> this.setState({position: 1}), 3000)
            },

            componentWillUnmount: () => {
              clearTimeout(myVar);
             };
            render: function () {
                 return (
                    <div className="component">
                        {this.state.position}
                    </div>
                 ); 
            }

        });

ReactDOM.render(
    <Component />,
    document.getElementById('main')
);

12

ฉันรู้ว่านี่เก่าไปหน่อย แต่สิ่งสำคัญคือต้องสังเกตว่า React แนะนำให้ล้างช่วงเวลาเมื่อยกเลิกการต่อเชื่อมส่วนประกอบ: https://reactjs.org/docs/state-and-lifecycle.html

ดังนั้นฉันต้องการเพิ่มคำตอบนี้ในการสนทนานี้:

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }
  componentWillUnmount() {
    clearInterval(this.timerID);
  }

8

setStateจะถูกเรียกใช้ทันทีเนื่องจากวงเล็บ! รวมไว้ในฟังก์ชันที่ไม่ระบุตัวตนจากนั้นเรียกมันว่า:

setTimeout(function() {
    this.setState({position: 1})
}.bind(this), 3000);

6

คุณไม่ได้บอกว่าใครเรียก setTimeout

นี่คือวิธีที่คุณเรียกการหมดเวลาโดยไม่ต้องเรียกใช้ฟังก์ชันเพิ่มเติม

1. คุณสามารถทำได้โดยไม่ต้องสร้างฟังก์ชันเพิ่มเติม

setTimeout(this.setState.bind(this, {position:1}), 3000);

ใช้function.prototype.bind ()

setTimeout ใช้ตำแหน่งของฟังก์ชันและเก็บไว้ในบริบท

2. อีกวิธีหนึ่งในการทำเช่นเดียวกันโดยการเขียนโค้ดแม้แต่น้อย

setTimeout(this.setState, 3000, {position:1});

อาจใช้วิธีผูกแบบเดียวกันในบางจุด

setTimeout ใช้เฉพาะตำแหน่งของฟังก์ชันและฟังก์ชันมีบริบทอยู่แล้ว? อย่างไรก็ตามมันได้ผล!

หมายเหตุ: สิ่งเหล่านี้ใช้ได้กับฟังก์ชันใด ๆ ที่คุณใช้ใน js


5

ขอบเขตรหัสของคุณ ( this)จะเป็นwindowวัตถุของคุณไม่ใช่องค์ประกอบการตอบสนองของคุณและนั่นคือสาเหตุที่setTimeout(this.setState({position: 1}), 3000)ทำให้เกิดความผิดพลาดในลักษณะนี้

ที่มาจาก javascript not React เป็นการปิด js


ดังนั้นในการผูกขอบเขตองค์ประกอบปฏิกิริยาปัจจุบันของคุณให้ทำสิ่งนี้:

setTimeout(function(){this.setState({position: 1})}.bind(this), 3000);

หรือหากเบราว์เซอร์ของคุณรองรับ es6 หรือ projs ของคุณรองรับการคอมไพล์ es6 ถึง es5 ให้ลองใช้ฟังก์ชัน arrow ด้วยเช่นกันเนื่องจาก arrow func คือการแก้ไขปัญหา "this":

setTimeout(()=>this.setState({position: 1}), 3000);

3

มี 3 วิธีในการเข้าถึงขอบเขตภายในฟังก์ชัน 'setTimeout'

ประการแรก

const self = this
setTimeout(function() {
  self.setState({position:1})
}, 3000)

ประการที่สองคือการใช้ฟังก์ชันลูกศร ES6 ทำให้ฟังก์ชันลูกศรไม่มีขอบเขต (สิ่งนี้)

setTimeout(()=> {
   this.setState({position:1})
}, 3000)

ประการที่สามคือการผูกขอบเขตภายในฟังก์ชัน

setTimeout(function(){
   this.setState({position:1})
}.bind(this), 3000)

1

คุณทำผิดพลาดในการประกาศไวยากรณ์ใช้การประกาศ setTimeout ที่เหมาะสม

message:() => { 
  setTimeout(() => {this.setState({opened:false})},3000); 
  return 'Thanks for your time, have a nice day 😊! 
}

0

พยายามใช้ไวยากรณ์ ES6 ของ set timeout javascript ปกติ setTimeout () จะไม่ทำงานใน react js

setTimeout(
      () => this.setState({ position: 100 }), 
      5000
    );
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.