React.js รอให้ setState เสร็จสิ้นก่อนเรียกใช้ฟังก์ชัน?


108

นี่คือสถานการณ์ของฉัน:

  • บน this.handleFormSubmit () ฉันกำลังดำเนินการ this.setState ()
  • ภายใน this.handleFormSubmit () ฉันกำลังเรียกสิ่งนี้ว่า findRoutes (); - ซึ่งขึ้นอยู่กับความสำเร็จของ this.setState ()
  • this.setState (); ไม่เสร็จสมบูรณ์ก่อนหน้านี้ findRoutes เรียกว่า ...
  • ฉันจะรอให้ this.setState () ใน this.handleFormSubmit () เสร็จสิ้นก่อนที่จะเรียก this.findRoutes () ได้อย่างไร

โซลูชันย่อย:

  • วาง this.findRoutes () ใน componentDidUpdate ()
  • สิ่งนี้ไม่สามารถยอมรับได้เนื่องจากจะมีการเปลี่ยนแปลงสถานะอื่น ๆ ที่ไม่เกี่ยวข้องกับฟังก์ชัน findRoutes () ฉันไม่ต้องการเรียกใช้ฟังก์ชัน findRoutes () เมื่อมีการอัปเดตสถานะที่ไม่เกี่ยวข้อง

โปรดดูข้อมูลโค้ดด้านล่าง:

handleFormSubmit: function(input){
                // Form Input
                this.setState({
                    originId: input.originId,
                    destinationId: input.destinationId,
                    radius: input.radius,
                    search: input.search
                })
                this.findRoutes();
            },
            handleMapRender: function(map){
                // Intialized Google Map
                directionsDisplay = new google.maps.DirectionsRenderer();
                directionsService = new google.maps.DirectionsService();
                this.setState({map: map});
                placesService = new google.maps.places.PlacesService(map);
                directionsDisplay.setMap(map);
            },
            findRoutes: function(){
                var me = this;
                if (!this.state.originId || !this.state.destinationId) {
                    alert("findRoutes!");
                    return;
                }
                var p1 = new Promise(function(resolve, reject) {
                    directionsService.route({
                        origin: {'placeId': me.state.originId},
                        destination: {'placeId': me.state.destinationId},
                        travelMode: me.state.travelMode
                    }, function(response, status){
                        if (status === google.maps.DirectionsStatus.OK) {
                            // me.response = response;
                            directionsDisplay.setDirections(response);
                            resolve(response);
                        } else {
                            window.alert('Directions config failed due to ' + status);
                        }
                    });
                });
                return p1
            },
            render: function() {
                return (
                    <div className="MapControl">
                        <h1>Search</h1>
                        <MapForm
                            onFormSubmit={this.handleFormSubmit}
                            map={this.state.map}/>
                        <GMap
                            setMapState={this.handleMapRender}
                            originId= {this.state.originId}
                            destinationId= {this.state.destinationId}
                            radius= {this.state.radius}
                            search= {this.state.search}/>
                    </div>
                );
            }
        });

คำตอบ:


251

setState()มีพารามิเตอร์การเรียกกลับที่เป็นทางเลือกซึ่งคุณสามารถใช้สำหรับสิ่งนี้ คุณต้องเปลี่ยนรหัสของคุณเพียงเล็กน้อยเพื่อทำสิ่งนี้:

// Form Input
this.setState(
  {
    originId: input.originId,
    destinationId: input.destinationId,
    radius: input.radius,
    search: input.search
  },
  this.findRoutes         // here is where you put the callback
);

สังเกตว่าการโทรถึงfindRoutesอยู่ในการsetState()โทรเป็นพารามิเตอร์ที่สอง
โดยไม่ต้อง()เพราะคุณกำลังผ่านฟังก์ชั่น


2
สุดทึ่ง! ขอบคุณมาก
malexanders

สิ่งนี้จะใช้ได้ดีสำหรับการรีเซ็ต AnimatedValue หลังจาก setState ใน ReactNative
SacWebDeveloper

เยี่ยมมาก ~ ขอบคุณมาก
吳強福

2
รุ่นทั่วไปthis.setState({ name: "myname" }, function() { console.log("setState completed", this.state) })
Sasi Varunan

ดูเหมือนว่าคุณสามารถส่งการติดต่อกลับไปยัง setState ได้มากกว่าหนึ่งครั้ง มีวิธีผูกมัดการโทรกลับที่ไม่ยุ่งเหยิงหรือไม่? สมมติว่าฉันมี 3 วิธีที่ต้องใช้ทั้งหมดและสถานะการอัปเดตทั้งหมด วิธีที่ดีที่สุดในการจัดการนี้คืออะไร?
Sean


10

ตามเอกสารของรัฐใหม่อาจจะไม่ได้รับการสะท้อนให้เห็นในฟังก์ชันการเรียกกลับsetState() findRoutes()นี่คือสารสกัดจากReact docs :

setState () ไม่กลายพันธุ์ this.state ทันที แต่สร้างการเปลี่ยนแปลงสถานะที่รอดำเนินการ การเข้าถึง this.state หลังจากเรียกเมธอดนี้สามารถคืนค่าที่มีอยู่ได้

ไม่มีการรับประกันการทำงานแบบซิงโครนัสของการโทรไปยัง setState และการโทรอาจเป็นกลุ่มเพื่อเพิ่มประสิทธิภาพ

นี่คือสิ่งที่ฉันเสนอว่าคุณควรทำ คุณควรจะผ่านการรัฐใหม่ในฟังก์ชันการเรียกกลับinputfindRoutes()

handleFormSubmit: function(input){
    // Form Input
    this.setState({
        originId: input.originId,
        destinationId: input.destinationId,
        radius: input.radius,
        search: input.search
    });
    this.findRoutes(input);    // Pass the input here
}

findRoutes()ฟังก์ชั่นควรจะกำหนดเช่นนี้

findRoutes: function(me = this.state) {    // This will accept the input if passed otherwise use this.state
    if (!me.originId || !me.destinationId) {
        alert("findRoutes!");
        return;
    }
    var p1 = new Promise(function(resolve, reject) {
        directionsService.route({
            origin: {'placeId': me.originId},
            destination: {'placeId': me.destinationId},
            travelMode: me.travelMode
        }, function(response, status){
            if (status === google.maps.DirectionsStatus.OK) {
                // me.response = response;
                directionsDisplay.setDirections(response);
                resolve(response);
            } else {
                window.alert('Directions config failed due to ' + status);
            }
        });
    });
    return p1
}

สิ่งนี้มีข้อบกพร่องร้ายแรง - การส่ง obj ตามตัวอักษรไปsetState()เนื่องจากสถานะใหม่ไม่ดีเนื่องจากนำไปสู่เงื่อนไขการแข่งขัน
tar

นี่คือคำพูดอื่นจากเอกสารการตอบสนอง (ซึ่งอาจได้รับการอัปเดตตั้งแต่คุณโพสต์คำตอบของคุณ): "... ใช้ componentDidUpdate หรือการเรียกกลับ setState (setState (ตัวอัปเดตการโทรกลับ)) ซึ่งรับประกันว่าจะเริ่มทำงานหลังจากการอัปเดต ถูกนำไปใช้ ". สิ่งนี้บอกกับฉันว่าสถานะใหม่นั้นสะท้อนให้เห็นอย่างแน่นอนที่สุดในฟังก์ชันเรียกกลับ
Andy

1

setState รับสถานะใหม่และฟังก์ชันเรียกกลับที่เป็นทางเลือกซึ่งถูกเรียกใช้หลังจากสถานะได้รับการอัพเดต

this.setState(
  {newState: 'whatever'},
  () => {/*do something after the state has been updated*/}
)

0

ทำไมไม่ตอบอีก? setState()และsetState()-triggered render()มีทั้งการดำเนินการที่เสร็จสมบูรณ์เมื่อคุณเรียกใช้componentDidMount()(ครั้งแรกrender()จะถูกเรียกใช้) และ / หรือcomponentDidUpdate()(เมื่อใดก็ได้หลังจากrender()ถูกเรียกใช้งาน) (ลิงก์ไปยังเอกสาร ReactJS.org)

ตัวอย่างด้วย componentDidUpdate()

ผู้โทรตั้งค่าการอ้างอิงและตั้งสถานะ ...

<Cmp ref={(inst) => {this.parent=inst}}>;
this.parent.setState({'data':'hello!'});

แสดงผู้ปกครอง ...

componentDidMount() {           // componentDidMount() gets called after first state set
    console.log(this.state.data);   // output: "hello!"
}
componentDidUpdate() {          // componentDidUpdate() gets called after all other states set
    console.log(this.state.data);   // output: "hello!"
}

ตัวอย่างด้วย componentDidMount()

ผู้โทรตั้งค่าการอ้างอิงและตั้งสถานะ ...

<Cmp ref={(inst) => {this.parent=inst}}>
this.parent.setState({'data':'hello!'});

แสดงผู้ปกครอง ...

render() {              // render() gets called anytime setState() is called
    return (
        <ChildComponent
            state={this.state}
        />
    );
}

หลังจากที่เด็ก rerenders componentDidUpdate()แม่เห็นของรัฐใน

componentDidMount() {           // componentDidMount() gets called anytime setState()/render() finish
console.log(this.props.state.data); // output: "hello!"
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.