2016-03-18 16 views
56

Tôi vừa phát hiện ra rằng trong phản ứng this.setState() chức năng trong bất kỳ thành phần là không đồng bộ hoặc được gọi sau khi hoàn thành các chức năng mà nó được gọi trong.setstate trong reactjs là Async hoặc Sync

Bây giờ tôi đã tìm kiếm và tìm thấy blog này (http://www.bennadel.com/blog/2893-setstate-state-mutation-operation-may-be-synchronous-in-reactjs.htm)

Tại đây, ông thấy rằng setState không đồng bộ (được gọi khi ngăn xếp trống) hoặc đồng bộ hóa (gọi ngay sau khi được gọi) tùy thuộc vào cách thay đổi trạng thái được kích hoạt.

Bây giờ hai điều này rất khó tiêu hóa

  1. Trong blog chức năng setstate được gọi là bên trong một updateState chức năng bây giờ những gì kích hoạt chức năng updateState không phải là cái gì đó một chức năng gọi là có thể biết được về.
  2. Tại sao chúng làm cho setState không đồng bộ như JS là ngôn ngữ đơn luồng và setState này không phải là một cuộc gọi WebAPI hay máy chủ nên chỉ được thực hiện trên chuỗi của JS. người nghe sự kiện và nội dung hoặc có một số vấn đề thiết kế khác.
+1

Xem http://stackoverflow.com/questions/28922275/in-reactjs-why-does-setstate-behave-differently-when-called-synchronously – lux

Trả lời

43

1.) hành động setState không đồng bộ và được phân đoạn để đạt được hiệu suất. Điều này được giải thích trong tài liệu của setState.

setState() không ngay lập tức biến đổi this.state nhưng tạo trạng thái chuyển tiếp đang chờ xử lý. Truy cập this.state sau khi gọi phương thức này có khả năng trả về giá trị hiện tại. Không có sự đảm bảo về hoạt động đồng bộ của các cuộc gọi đến setState và các cuộc gọi có thể được thực hiện theo đợt để đạt được hiệu suất.


2.) Tại sao họ sẽ làm cho setstate async như JS là ngôn ngữ đơn luồng và setstate đây không phải là một WebAPI hoặc máy chủ gọi:

Điều này là do setstate làm thay đổi trạng thái và gây rerendering. Đây có thể là một hoạt động tốn kém và làm cho nó đồng bộ có thể khiến trình duyệt không phản hồi.
Do đó, các cuộc gọi setState không đồng bộ cũng như theo đợt để có trải nghiệm và hiệu suất giao diện người dùng tốt hơn.

+33

Nếu bạn cần đảm bảo sắp xếp các sự kiện sau khi cuộc gọi setState được thực hiện , bạn có thể chuyển một hàm gọi lại. 'this.setState ({something: true},() => console.log (this.state))' – ianks

+0

Cảm ơn bạn @Sachin vì đã giải thích. Tuy nhiên, tôi vẫn còn nghi ngờ, nó có thể được đồng bộ như blog giải thích? –

80

Bạn có thể gọi một chức năng sau khi giá trị nhà nước đã được cập nhật:

this.setState({foo: 'bar'},() => { 
    // Do something here. 
}); 

Ngoài ra, nếu bạn có rất nhiều quốc gia để cập nhật cùng một lúc, nhóm chúng tất cả trong cùng một setState:

Instead of: 

this.setState({foo: "one"},() => { 
    this.setState({bar: "two"}); 
}); 


just do this: 

this.setState({ 
    foo: "one", 
    bar: "two" 
}); 
+5

ya thats ok, chúng tôi có một chức năng gọi lại, chúng tôi có thể sử dụng nhưng không phải là câu hỏi. – Anup

+6

Hy vọng rằng nó sẽ giúp người khác tình cờ gặp phải câu hỏi này. – JoeTidee

+0

ya dat có thể hữu ích – Anup

0

Bài viết hay tại đây https://github.com/vasanthk/react-bits/blob/master/patterns/27.passing-function-to-setState.md

// assuming this.state.count === 0 
this.setState({count: this.state.count + 1}); 
this.setState({count: this.state.count + 1}); 
this.setState({count: this.state.count + 1}); 
// this.state.count === 1, not 3 

Solution 
this.setState((prevState, props) => ({ 
    count: prevState.count + props.increment 
})); 

hoặc chuyển cuộc gọi lại this.setState ({.....},callback)

https://medium.com/javascript-scene/setstate-gate-abc10a9b2d82 https://medium.freecodecamp.org/functional-setstate-is-the-future-of-react-374f30401b6b

2

Tôi biết câu hỏi này là cũ, nhưng nó đã gây ra rất nhiều rắc rối cho nhiều người dùng reactjs trong một thời gian dài, trong đó có tôi. Gần đây Dan Abramov (từ nhóm phản ứng) chỉ viết lên một lời giải thích tuyệt vời như tại sao bản chất của setState là async:

https://github.com/facebook/react/issues/11527#issuecomment-360199710

setState được hiểu là không đồng bộ, và họ là một vài lý do thực sự tốt cho điều đó trong lời giải thích được liên kết bởi Dan Abramov. Điều này không có nghĩa là luôn luôn không đồng bộ - điều này chủ yếu có nghĩa là bạn không thể phụ thuộc vào nó là đồng bộ. ReactJS xem xét nhiều biến trong kịch bản mà bạn đang thay đổi trạng thái, để quyết định khi nào 'trạng thái' thực sự cần được cập nhật và thành phần của bạn được hiển thị lại.
Một ví dụ đơn giản để chứng minh điều này, là nếu bạn gọi setState là phản ứng với hành động của người dùng, thì trạng thái có thể sẽ được cập nhật ngay lập tức (mặc dù, bạn không thể tin tưởng), vì vậy người dùng đã thắng ' t cảm thấy chậm trễ, nhưng nếu bạn gọi setState để phản hồi một phản hồi cuộc gọi ajax hoặc một số sự kiện khác không được người dùng kích hoạt, thì trạng thái có thể được cập nhật với một chút chậm trễ, vì người dùng sẽ không thực sự cảm thấy điều này chậm trễ, và nó sẽ cải thiện hiệu suất bằng cách chờ đợi để cập nhật nhiều bản cập nhật trạng thái cùng nhau và hiển thị lại DOM ít lần hơn.

+0

ya chưa đánh dấu bất kỳ người trả lời nào là người trả lời đúng. Mọi người đang đăng tải cách thực hiện. Không phải là câu trả lời cho câu hỏi được hỏi. bài viết này có vẻ tốt. – Anup

+0

@Anup Câu trả lời phức tạp hơn một chút so với 'async' hoặc 'sync'. Nó luôn luôn được coi là 'không đồng bộ', nhưng trong một số trường hợp có thể hành động 'đồng bộ'. Tôi hy vọng tôi làm sáng tỏ cho bạn. – gillyb

0

Imagine incrementing một truy cập trong một số thành phần:

class SomeComponent extends Component{ 

    state = { 
     updatedByDiv: '', 
     updatedByBtn: '', 
     counter: 0 
    } 

    divCountHandler =() => { 
     this.setState({ 
     updatedByDiv: 'Div', 
     counter: this.state.counter + 1 
     }); 
     console.log('divCountHandler executed'); 
    } 

    btnCountHandler =() => { 
     this.setState({ 
     updatedByBtn: 'Button', 
     counter: this.state.counter + 1 
     }); 
     console.log('btnCountHandler executed'); 
    } 
    ... 
    ... 
    render(){ 
     return (
     ... 
     // a parent div 
     <div onClick={this.divCountHandler}> 
      // a child button 
      <button onClick={this.btnCountHandler}>Increment Count</button> 
     </div> 
     ... 
    ) 
    } 
    } 

Có một handler đếm gắn liền với cả phụ huynh và các thành phần con. Điều này được thực hiện cố ý để chúng ta có thể thực hiện setState() hai lần trong cùng một sự kiện nhấp chuột bubbling context, nhưng từ bên trong 2 trình xử lý khác nhau. Như chúng ta sẽ tưởng tượng, một sự kiện nhấp chuột duy nhất trên nút sẽ kích hoạt cả hai trình xử lý này kể từ khi bong bóng sự kiện từ mục tiêu đến vùng chứa ngoài cùng trong giai đoạn tạo bọt.

Do đó btnCountHandler() thực hiện đầu tiên, dự kiến ​​sẽ làm tăng số lần cho 1 và sau đó là divCountHandler() thực hiện, dự kiến ​​sẽ làm tăng số lần để 2.

Tuy nhiên số lượng chỉ increments tới 1 như bạn có thể kiểm tra trong công cụ React Developer.

này chứng minh rằng phản ứng

  • hàng đợi tất cả các setstate gọi

  • trở lại vào hàng đợi này sau khi thực hiện phương pháp cuối cùng trong bối cảnh (các divCountHandler trong trường hợp này)

  • kết hợp tất cả các đột biến đối tượng xảy ra trong nhiều cuộc gọi setState trong cùng một ngữ cảnh (tất cả các cuộc gọi phương thức trong một pha sự kiện đơn lẻ là cùng một bối cảnh ví dụ) thành một cú pháp đột biến đối tượng đơn lẻ. e vì đây là lý do tại sao chúng tôi có thể cập nhật các thuộc tính trạng thái độc lập trong setState() ở vị trí đầu tiên)

  • và chuyển nó vào một setState() đơn lẻ để ngăn hiển thị lại do nhiều lệnh setState() một mô tả rất nguyên thủy của đợt).

đang Resultant chạy bằng phản ứng:

this.setState({ 
    updatedByDiv: 'Div', 
    updatedByBtn: 'Button', 
    counter: this.state.counter + 1 
}) 

Để ngăn chặn hành vi này, thay vì đi qua đối tượng như các đối số cho phương thức setstate, callbacks được thông qua.

divCountHandler =() => { 
      this.setState((prevState, props) => { 
      return { 
       updatedByDiv: 'Div', 
       counter: prevState.counter + 1 
      }; 
      }); 
      console.log('divCountHandler executed'); 
     } 

    btnCountHandler =() => { 
      this.setState((prevState, props) => { 
      return { 
       updatedByBtn: 'Button', 
       counter: prevState.counter + 1 
      }; 
      }); 
     console.log('btnCountHandler executed'); 
    } 

Sau khi phương thức cuối cùng kết thúc thực hiện và khi phản hồi trả về để xử lý hàng đợi setState, nó gọi đơn giản gọi lại cho mỗi setState xếp hàng, đi qua trạng thái thành phần trước đó.

Cách này phản ứng đảm bảo rằng lần gọi lại cuối cùng trong hàng đợi được cập nhật trạng thái mà tất cả các đối tác trước đó của nó đã đặt tay lên.

Các vấn đề liên quan