Khi nào nên sử dụng gọi lại React setState


191

Khi một trạng thái thành phần phản ứng thay đổi, phương thức kết xuất được gọi. Do đó đối với bất kỳ thay đổi trạng thái nào, một hành động có thể được thực hiện trong thân phương thức kết xuất. Có trường hợp sử dụng cụ thể nào cho cuộc gọi lại setState không?


4
Hiện tại vẫn chưa rõ những gì bạn đang hỏi. Bạn có thể bao gồm một số mã?
Davin Tryon

2
Cuộc gọi lại setState dành cho bất cứ điều gì bạn muốn làm sau khi trạng thái DEFINITELYbeen thay đổi. Vì setState không đồng bộ, nên nếu bạn muốn gọi fx và CHẮC CHẮN rằng trạng thái mới được tải thì đó là những gì cuộc gọi lại dành cho
Jayce444

3
Trường hợp sử dụng cho cuộc gọi lại setState khá rõ ràng. Bạn sử dụng nó khi bạn muốn một chức năng chạy sau khi trạng thái CỤ THỂ đã được cập nhật. Nếu bạn đặt chức năng này render()thay vào đó, nó sẽ chạy mỗi khi BẤT K state trạng thái nào được cập nhật, đây có thể không phải là điều bạn muốn. Điều này cũng sẽ làm cho mã của bạn ít đọc và logic hơn.
M3RS

Câu trả lời:


222

Có, vì setStatelàm việc theo một asynchronouscách. Đó là phương tiện sau khi gọi setStatecác this.statebiến không ngay lập tức thay đổi. vì vậy nếu bạn muốn thực hiện một hành động ngay sau khi đặt trạng thái trên một biến trạng thái và sau đó trả về một kết quả, một cuộc gọi lại sẽ hữu ích

Hãy xem xét ví dụ dưới đây

....
changeTitle: function changeTitle (event) {
  this.setState({ title: event.target.value });
  this.validateTitle();
},
validateTitle: function validateTitle () {
  if (this.state.title.length === 0) {
    this.setState({ titleError: "Title can't be blank" });
  }
},
....

Đoạn mã trên có thể không hoạt động như mong đợi vì titlebiến có thể không bị đột biến trước khi xác thực được thực hiện trên nó. Bây giờ bạn có thể tự hỏi rằng chúng ta có thể thực hiện xác thực trong render()chính chức năng đó nhưng sẽ tốt hơn và tốt hơn nếu chúng ta có thể xử lý việc này trong chính hàm ChangeTitle vì điều đó sẽ giúp mã của bạn có tổ chức và dễ hiểu hơn

Trong trường hợp này gọi lại là hữu ích

....
changeTitle: function changeTitle (event) {
  this.setState({ title: event.target.value }, function() {
    this.validateTitle();
  });

},
validateTitle: function validateTitle () {
  if (this.state.title.length === 0) {
    this.setState({ titleError: "Title can't be blank" });
  }
},
....

Một ví dụ khác sẽ là khi bạn muốn dispatchvà hành động khi trạng thái thay đổi. bạn sẽ muốn thực hiện nó trong một cuộc gọi lại chứ không phải render()vì nó sẽ được gọi mỗi lần tái xuất hiện và do đó nhiều kịch bản như vậy có thể xảy ra khi bạn sẽ cần gọi lại.

Một trường hợp khác là một API Call

Một trường hợp có thể phát sinh khi bạn cần thực hiện lệnh gọi API dựa trên thay đổi trạng thái cụ thể, nếu bạn thực hiện điều đó trong phương thức kết xuất, nó sẽ được gọi trên mỗi onStatethay đổi kết xuất hoặc do một số Prop được chuyển sang Child Componentthay đổi.

Trong trường hợp này, bạn sẽ muốn sử dụng một setState callbackđể chuyển giá trị trạng thái được cập nhật cho lệnh gọi API

....
changeTitle: function (event) {
  this.setState({ title: event.target.value }, () => this.APICallFunction());
},
APICallFunction: function () {
  // Call API with the updated value
}
....

3
Tôi hiểu rằng nó không đồng bộ trong tự nhiên. Câu hỏi của tôi là có một cái gì đó cụ thể mà chỉ có thể sử dụng hàm gọi lại setState mà có lẽ cơ thể phương thức kết xuất có thể không hỗ trợ (Một cái gì đó ngoài việc nói khả năng đọc mã tốt hơn.)
Sahil Jain

@SahilJain Xác thực là ví dụ chính xác, bạn sẽ không muốn xử lý nó trong hàm render () bởi vì sau đó nó sẽ được gọi mỗi khi bạn thực hiện bất kỳ thay đổi nào trong kết xuất () mà bạn chỉ muốn gọi nó khi chỉ thay đổi đầu vào và do đó trong chính chức năng
Shubham Khatri

React cấm thay đổi trạng thái trong quá trình kết xuất .. Vì vậy, quyền đưa xác thực vào cuộc gọi lại.
webdeb

if (this.title.length === 0) {nên this.state.title.length, phải không?
Dmitry Minkovsky

4
Trường hợp sử dụng đầu tiên có lẽ không phải là một ý tưởng tốt. setState kích hoạt gọi lại sau khi kết xuất lại, vì vậy bạn đang gây ra kết xuất kép không có lý do chính đáng. Đây chính xác là mục đích của đối số chức năng (updater). Bạn chỉ có thể chạy setState(state => state.title.length ? { titleError: "Title can't be blank" } : null)và thay đổi sẽ ngăn xếp. Không có kết xuất đôi cần thiết.
R Esmond

46
this.setState({
    name:'value' 
},() => {
    console.log(this.state.name);
});

14
Cảm ơn bạn vì đoạn mã này, có thể cung cấp một số trợ giúp hạn chế, ngay lập tức. Một lời giải thích phù hợp sẽ cải thiện đáng kể giá trị lâu dài của nó bằng cách chỉ ra lý do tại sao đây là một giải pháp tốt cho vấn đề và sẽ giúp nó hữu ích hơn cho những người đọc tương lai với những câu hỏi tương tự khác. Vui lòng chỉnh sửa câu trả lời của bạn để thêm một số giải thích, bao gồm các giả định bạn đã thực hiện.
Machavity

1
Khi bạn muốn gọi một hàm sau khi trạng thái thay đổi, bạn có thể sử dụng phương thức.
Araz Babayev

Điều gì nếu bạn muốn thiết lập nhiều độ xốp của trạng thái như tên, tên, v.v.?
Sumanth Varada

44

1. usecase xuất hiện trong tâm trí tôi, là một apicuộc gọi, không nên đi vào kết xuất, bởi vì nó sẽ chạy để eachthay đổi trạng thái. Và lệnh gọi API chỉ nên được thực hiện khi thay đổi trạng thái đặc biệt chứ không phải trên mỗi kết xuất.

changeSearchParams = (params) => {
  this.setState({ params }, this.performSearch)
} 

performSearch = () => {
  API.search(this.state.params, (result) => {
    this.setState({ result })
  });
}

Do đó đối với bất kỳ thay đổi trạng thái nào, một hành động có thể được thực hiện trong thân phương thức kết xuất.

Thực tiễn rất tệ , bởi vì render-method nên thuần túy, điều đó có nghĩa là không có hành động, thay đổi trạng thái, cuộc gọi api, nên được thực hiện, chỉ cần tổng hợp quan điểm của bạn và trả lại nó. Các hành động chỉ nên được thực hiện trên một số sự kiện. Kết xuất không phải là một sự kiện, nhưng componentDidMountví dụ.


25

Xem xét cuộc gọi setState

this.setState({ counter: this.state.counter + 1 })

Ý TƯỞNG

setState có thể được gọi trong hàm async

Vì vậy, bạn không thể dựa vào this. Nếu cuộc gọi trên được thực hiện bên trong chức năng async thissẽ đề cập đến trạng thái của thành phần tại thời điểm đó nhưng chúng tôi hy vọng điều này sẽ đề cập đến thuộc tính bên trong trạng thái tại thời điểm setState gọi hoặc bắt đầu tác vụ async. Và vì nhiệm vụ là cuộc gọi không đồng bộ, do đó, thuộc tính có thể đã thay đổi theo thời gian. Do đó, không đáng tin cậy khi sử dụng thistừ khóa để chỉ một số thuộc tính của trạng thái, do đó chúng tôi sử dụng hàm gọi lại có đối số là trướcState và đạo cụ, nghĩa là khi tác vụ async được thực hiện và đã đến lúc cập nhật trạng thái bằng cách sử dụng lệnh setState chưa bắt đầu Đảm bảo độ tin cậy rằng nextState sẽ không bị hỏng.

Mã sai: sẽ dẫn đến tham nhũng dữ liệu

this.setState(
   {counter:this.state.counter+1}
 );

Mã chính xác với setState có chức năng gọi lại:

 this.setState(
       (prevState,props)=>{
           return {counter:prevState.counter+1};
        }
    );

Do đó, bất cứ khi nào chúng ta cần cập nhật trạng thái hiện tại của mình sang trạng thái tiếp theo dựa trên giá trị mà tài sản sở hữu ngay bây giờ và tất cả điều này đang diễn ra theo kiểu không đồng bộ, tốt nhất là sử dụng setState làm chức năng gọi lại.

Tôi đã cố gắng giải thích nó trong codepen ở đây CODE PEN

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.