Tôi làm việc trên React.
TLDR:
Nhưng bạn có thể tin tưởng React để cập nhật trạng thái theo thứ tự như setState được gọi cho
Đúng.
Đúng.
Thứ tự cập nhật luôn được tôn trọng. Việc bạn có thấy trạng thái trung gian "giữa" chúng hay không phụ thuộc vào việc bạn có ở trong một lô hay không.
Hiện tại (React 16 trở về trước), chỉ các bản cập nhật bên trong trình xử lý sự kiện React được bó theo mặc định . Có một API không ổn định để buộc hàng loạt bên ngoài các trình xử lý sự kiện cho các trường hợp hiếm khi bạn cần.
Trong các phiên bản trong tương lai (có thể là React 17 trở lên), React sẽ bó tất cả các bản cập nhật theo mặc định để bạn không phải suy nghĩ về điều này. Như mọi khi, chúng tôi sẽ thông báo bất kỳ thay đổi nào về điều này trên blog React và trong ghi chú phát hành.
Chìa khóa để hiểu điều này là cho dù có bao nhiêu setState()
cuộc gọi trong bao nhiêu thành phần bạn thực hiện trong trình xử lý sự kiện React , chúng sẽ chỉ tạo ra một lần kết xuất lại vào cuối sự kiện . Điều này rất quan trọng để có hiệu suất tốt trong các ứng dụng lớn vì nếu Child
và Parent
mỗi cuộc gọi setState()
khi xử lý một sự kiện nhấp chuột, bạn không muốn kết xuất lại Child
hai lần.
Trong cả hai ví dụ của bạn, setState()
các cuộc gọi xảy ra bên trong trình xử lý sự kiện React. Do đó, chúng luôn được tuôn ra cùng nhau vào cuối sự kiện (và bạn không thấy trạng thái trung gian).
Các bản cập nhật luôn được hợp nhất một cách nông cạn theo thứ tự chúng xảy ra . Vì vậy, nếu bản cập nhật đầu tiên là {a: 10}
, thứ hai là {b: 20}
và thứ ba là {a: 30}
, trạng thái kết xuất sẽ là {a: 30, b: 20}
. Bản cập nhật gần đây hơn cho cùng một khóa trạng thái (ví dụ như a
trong ví dụ của tôi) luôn "thắng".
Đối this.state
tượng được cập nhật khi chúng ta kết xuất lại UI vào cuối đợt. Vì vậy, nếu bạn cần cập nhật trạng thái dựa trên trạng thái trước đó (chẳng hạn như tăng bộ đếm), bạn nên sử dụng setState(fn)
phiên bản chức năng cung cấp cho bạn trạng thái trước đó, thay vì đọc từ đó this.state
. Nếu bạn tò mò về lý do cho điều này, tôi đã giải thích sâu về nhận xét này .
Trong ví dụ của bạn, chúng tôi sẽ không thấy "trạng thái trung gian" vì chúng tôi đang ở trong trình xử lý sự kiện React nơi bật tính năng tạo khối (vì React "biết" khi chúng tôi thoát khỏi sự kiện đó).
Tuy nhiên, cả trong phiên bản React 16 và các phiên bản trước đó, vẫn chưa có đợt xử lý theo mặc định bên ngoài trình xử lý sự kiện React . Vì vậy, nếu trong ví dụ của bạn, chúng tôi có trình xử lý phản hồi AJAX thay vì handleClick
, mỗi cái setState()
sẽ được xử lý ngay khi nó xảy ra. Trong trường hợp này, có, bạn sẽ thấy trạng thái trung gian:
promise.then(() => {
// We're not in an event handler, so these are flushed separately.
this.setState({a: true}); // Re-renders with {a: true, b: false }
this.setState({b: true}); // Re-renders with {a: true, b: true }
this.props.setParentState(); // Re-renders the parent
});
Chúng tôi nhận thấy điều bất tiện là hành vi đó khác nhau tùy thuộc vào việc bạn có ở trong xử lý sự kiện hay không . Điều này sẽ thay đổi trong phiên bản React trong tương lai, sẽ bó tất cả các bản cập nhật theo mặc định (và cung cấp API chọn tham gia để xóa các thay đổi một cách đồng bộ). Cho đến khi chúng tôi chuyển đổi hành vi mặc định (có khả năng trong Phản ứng 17), có một API bạn có thể sử dụng để buộc thực hiện theo đợt :
promise.then(() => {
// Forces batching
ReactDOM.unstable_batchedUpdates(() => {
this.setState({a: true}); // Doesn't re-render yet
this.setState({b: true}); // Doesn't re-render yet
this.props.setParentState(); // Doesn't re-render yet
});
// When we exit unstable_batchedUpdates, re-renders once
});
Tất cả các trình xử lý sự kiện React Internal đều được gói gọn trong unstable_batchedUpdates
đó là lý do tại sao chúng được xử lý theo mặc định. Lưu ý rằng gói một bản cập nhật trong unstable_batchedUpdates
hai lần không có hiệu lực. Các bản cập nhật được tuôn ra khi chúng ta thoát khỏi unstable_batchedUpdates
cuộc gọi ngoài cùng .
API đó "không ổn định" theo nghĩa là chúng tôi sẽ xóa nó khi tính năng tạo khối đã được bật theo mặc định. Tuy nhiên, chúng tôi sẽ không xóa nó trong một phiên bản nhỏ, vì vậy bạn có thể dựa vào nó một cách an toàn cho đến khi React 17 nếu bạn cần buộc xử lý theo đợt trong một số trường hợp bên ngoài trình xử lý sự kiện React.
Tóm lại, đây là một chủ đề khó hiểu vì React chỉ có các lô bên trong trình xử lý sự kiện theo mặc định. Điều này sẽ thay đổi trong các phiên bản trong tương lai và hành vi sẽ đơn giản hơn sau đó. Nhưng giải pháp không phải là bó ít hơn , theo mặc định là bó nhiều hơn . Đó là những gì chúng ta sẽ làm.