Tại sao setState trong Reacjs Async thay vì Sync?


126

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

Bây giờ tôi đã tìm kiếm và tìm thấy blog này ( setState () Hoạt động đột biến trạng thái có thể đồng bộ trong ReactJS )

Ở đây, ông thấy rằng setStatekhông đồng bộ (được gọi khi ngăn xếp trống) hoặc đồng bộ hóa (được gọi ngay 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, setStatehàm được gọi bên trong một hàm updateState, nhưng cái đã kích hoạt updateStatehàm này không phải là thứ mà hàm được gọi sẽ biết.
  2. Tại sao họ tạo setStateasync như JS là ngôn ngữ luồng đơn và setState này không phải là một cuộc gọi máy chủ hoặc WebAPI nên chỉ được thực hiện trên luồng của JS. Có phải họ đang làm điều này để Re-Rendering không dừng tất cả những người nghe sự kiện và công cụ, hoặc có một số vấn đề thiết kế khác.


1
Tôi đã viết một bài báo hôm nay giúp mô tả một chút về khí hậu xung quanh setState: Medium.com/@agm1984/iêu
agm1984

Câu trả lời:


155

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

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

Ngoài ra, nếu bạn có nhiều trạng thái để cập nhật cùng một lúc, hãy nhóm tất cả chúng trong cùng một trạng thái setState:

Thay vì:

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

Chỉ cần làm điều này:

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

16
ya đó là ok chúng tôi có một chức năng callBack chúng tôi có thể sử dụng nhưng không phải là câu hỏi.
Anup

12
Hy vọng nó sẽ giúp người khác làm thế nào vấp phải câu hỏi này.
JoeTidee

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

97

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

setState () không ngay lập tức biến đổi this.state nhưng tạo ra một chuyển đổi trạng thái đ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 có. Không có gì đảm bảo cho 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ăng hiệu suất.


2) Tại sao họ sẽ tạo setState async vì JS là ngôn ngữ luồng đơn và đây setStatekhông phải là cuộc gọi máy chủ hoặc WebAPI?

Điều này là do setStatethay đổi nhà nước và gây ra sự đăng ký lại. Đây có thể là một hoạt động đắt tiền và làm cho nó đồng bộ có thể khiến trình duyệt không phản hồi.

Do đó, các lệnh gọi setState không đồng bộ cũng như theo đợt cho trải nghiệm và hiệu suất UI tốt hơn.


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

1
Cảm ơn bạn @Sachin đã giải thích. Tuy nhiên, tôi vẫn còn nghi ngờ, liệu nó có thể đồng bộ như blog giải thích không?
Bò tót Ajay

2
Một quyết định thiết kế ngu ngốc trong phản ứng. Làm cho cập nhật trạng thái đồng bộ và kết xuất không đồng bộ. Bạn có thể kết xuất hàng loạt, nhưng tôi muốn có thể đặt thứ gì đó nguyên thủy như các biến trạng thái mà không phải xử lý các điều kiện chủng tộc.
ig-dev

Tại sao không cho phép tùy chọn được đặt để tạo fucntion hoặc không đồng bộ hoặc đồng bộ hóa? Đó sẽ là một tính năng hữu ích
Mã hóa Randall

Rõ ràng, tôi không ở trong nhóm phản ứng mà theo một lý do, theo tôi, để thực hiện cập nhật trạng thái không đồng bộ là các trình duyệt được phân luồng đơn. Hoạt động đồng bộ hóa có thể làm cho UI không phản hồi và không phải là ứng cử viên tốt cho UI.
Sachin

16

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

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

setStatecó nghĩa là không đồng bộ, và có 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 của Dan Abramov. Điều này không có nghĩa là nó sẽ luôn không đồng bộ - điều đó chủ yếu có nghĩa là bạn không thể phụ thuộc vào nó là đồng bộ . ReactJS sẽ 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 statethực sự cần được cập nhật và thành phần của bạn được đăng ký lại.
Một ví dụ đơn giản để chứng minh điều này, là nếu bạn gọisetState là phản ứng với hành động của người dùng, thì statecó lẽ sẽ được cập nhật ngay lập tức (mặc dù, một lần nữa, bạn không thể tin vào điều đó), vì vậy người dùng sẽ không cảm thấy bất kỳ sự chậm trễ nào nhưng nếu bạn gọisetState phản ứng với phản hồi cuộc gọi ajax hoặc một số sự kiện khác không được kích hoạt bởi người dùng, sau đó 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 sự chậm trễ này và nó sẽ cải thiện hiệu suất bằng cách chờ hàng loạt cập nhật trạng thái cùng nhau và đăng ký lại DOM ít lần hơn.


ya đã không đánh dấu bất kỳ câu trả lời là đúng. Mọi người đang đăng làm thế nào để có được xung quanh nó. Không phải là câu trả lời cho câu hỏi. Bài viết này có vẻ tốt.
Anup

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

8

Bài viết hay ở đây https://github.com/vasanthk/react-bits/blob/master/potypes/27.passing-feft-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 vượt qua cuộc gọi lại this.setState ({.....},callback)

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



1

Hãy tưởng tượng việc tăng một bộ đếm 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 trình xử lý đếm được gắn vào cả hai thành phần cha và con. Điều này được thực hiện có chủ đích để chúng tôi có thể thực thi setState () hai lần trong cùng bối cảnh bong bóng sự kiện nhấp chuột, nhưng từ trong 2 trình xử lý khác nhau.

Như chúng ta tưởng tượng, một sự kiện nhấp chuột vào nút bây giờ sẽ kích hoạt cả hai trình xử lý này vì bong bóng sự kiện từ mục tiêu đến thùng chứa ngoài cùng trong giai đoạn sủi bọt.

Do đó, btnCountHandler () thực thi trước, dự kiến ​​sẽ tăng số đếm lên 1 và sau đó divCountHandler () thực thi, dự kiến ​​sẽ tăng số đếm lên 2.

Tuy nhiên, số lượng chỉ tăng lên 1 khi bạn có thể kiểm tra trong các công cụ React Developer.

Điều này chứng tỏ rằng phản ứng

  • xếp hàng tất cả các cuộc gọi setState

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

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

  • và chuyển nó vào một setState () duy nhất để ngăn kết xuất lại do nhiều lệnh gọi setState () (đây là một mô tả rất nguyên thủy về việc tạo khối).

Mã kết quả chạy bằng phản ứng:

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

Để dừng hành vi này, thay vì truyền các đối tượng làm đối số cho phương thức setState, các cuộc gọi lại đượ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 ứng trả về để xử lý hàng đợi setState, nó chỉ cần gọi lại cho mỗi setState được xếp hàng, chuyển qua trạng thái thành phần trước đó.

Cách phản ứng này đảm bảo rằng cuộc 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 đó đã đặt tay vào.


0

Có, setState () không đồng bộ.

Từ liên kết: https://reactjs.org/docs/react-component.html#setstate

  • React không đảm bảo rằng những thay đổi trạng thái được áp dụng ngay lập tức.
  • setState () không phải lúc nào cũng cập nhật thành phần ngay lập tức.
  • Hãy nghĩ về setState () như một yêu cầu thay vì một lệnh ngay lập tức để cập nhật thành phần.

Bởi vì họ nghĩ
Từ liên kết: https://github.com/facebook/react/issues/11527#issuecomment-360199710

... chúng tôi đồng ý rằng setState () kết xuất lại đồng bộ sẽ không hiệu quả trong nhiều trường hợp

SetState () không đồng bộ làm cho cuộc sống rất khó khăn cho những người bắt đầu và thậm chí không may gặp phải:
- sự cố kết xuất không mong muốn: kết xuất chậm hoặc không kết xuất (dựa trên logic chương trình)
- truyền tham số là
vấn đề lớn trong số các vấn đề khác.

Ví dụ dưới đây đã giúp:

// call doMyTask1 - here we set state
// then after state is updated...
//     call to doMyTask2 to proceed further in program

constructor(props) {
    // ..

    // This binding is necessary to make `this` work in the callback
    this.doMyTask1 = this.doMyTask1.bind(this);
    this.doMyTask2 = this.doMyTask2.bind(this);
}

function doMyTask1(myparam1) {
    // ..

    this.setState(
        {
            mystate1: 'myvalue1',
            mystate2: 'myvalue2'
            // ...
        },    
        () => {
            this.doMyTask2(myparam1); 
        }
    );
}

function doMyTask2(myparam2) {
    // ..
}

Mong rằng sẽ giúp.

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.