Làm cách nào để đặt lại thành phần phản ứng bao gồm tất cả trạng thái có thể truy cập chuyển tiếp?


93

Tôi thỉnh thoảng có các thành phần phản ứng có trạng thái khái niệm mà tôi muốn đặt lại. Hành vi lý tưởng sẽ tương đương với việc loại bỏ thành phần cũ và đọc một thành phần mới, nguyên sơ.

React cung cấp một phương thức setStatecho phép thiết lập trạng thái rõ ràng của riêng các thành phần, nhưng loại trừ trạng thái ngầm định như tiêu điểm của trình duyệt và trạng thái biểu mẫu, đồng thời nó cũng loại trừ trạng thái con của nó. Nắm bắt tất cả trạng thái gián tiếp đó có thể là một nhiệm vụ khó khăn, và tôi muốn giải quyết nó một cách chặt chẽ và hoàn chỉnh hơn là chơi whack-a-nốt ruồi với mọi trạng thái bất ngờ mới.

Có API hoặc mẫu nào để làm điều này không?

Chỉnh sửa: Tôi đã làm một ví dụ nhỏ minh họa this.replaceState(this.getInitialState())cách tiếp cận và đối chiếu nó với this.setState(this.getInitialState())cách tiếp cận: jsfiddle - replaceStatemạnh mẽ hơn.

Câu trả lời:


206

Để đảm bảo rằng trạng thái trình duyệt ngầm mà bạn đề cập và trạng thái con được đặt lại, bạn có thể thêm keythuộc tính vào thành phần cấp gốc được trả về render; khi nó thay đổi, thành phần đó sẽ bị vứt bỏ và tạo lại từ đầu.

render: function() {
    // ...
    return <div key={uniqueId}>
        {children}
    </div>;
}

Không có phím tắt nào để đặt lại trạng thái cục bộ của từng thành phần.


1
Chỉ vì tò mò khi bạn nói 'thành phần sẽ bị loại bỏ và được tạo lại từ đầu' có nghĩa là DOM ảo sẽ bị loại bỏ và tạo lại từ đầu nhưng các bản cập nhật DOM vẫn sẽ xảy ra dựa trên thuật toán khác biệt?
nimgrg

1
@nimgrg Không, các phần tử DOM thực cũng sẽ được tạo lại. (DOM ảo đã được tạo lại trên mỗi lần hiển thị, vì vậy nếu bạn muốn giữ DOM thực, chỉ cần không đặt một keytrong trường hợp này.)
Sophie Alpert

3
@EamonNerbonne Trên React 0.8, các khóa chỉ được sử dụng để phân biệt giữa các phần tử anh em trong một mảng và bị bỏ qua ở gốc. Xem github.com/facebook/react/issues/590 .
Sophie Alpert

Lưu ý replaceState()getInitialState()cả hai đều không được chấp nhận trong phản ứng kiểu lớp ES6 mới. Sử dụng this.setState(this._getInitialState())thay thế. Ngoài ra, bạn không thể đặt tên cho hàm khởi tạo trạng thái của riêng mình getInitialState()- phản ứng ném cảnh báo - gọi nó là bất kỳ thứ gì khác và thực hiện rõ ràng state = this._getInitialState()ở cấp cao nhất của lớp.
thom_nic

2
Có cách nào để thực hiện điều này từ bên trong của một thành phần mà không yêu cầu bên ngoài chuyển một chỗ dựa chính không?
trusktr

14

Bạn thực sự nên tránh replaceStatevà sử dụng setStatethay thế.

Tài liệu nói rằng replaceState"có thể bị xóa hoàn toàn trong phiên bản React trong tương lai." Tôi nghĩ nó chắc chắn sẽ bị loại bỏ vì replaceStatenó không thực sự phù hợp với triết lý của React. Nó tạo điều kiện thuận lợi cho việc làm cho một thành phần React bắt đầu cảm thấy giống như một con dao Thụy Sĩ. Điều này cản trở sự phát triển tự nhiên của một thành phần React khi trở nên nhỏ hơn và có mục đích hơn.

Trong React, nếu bạn phải sai lầm về tổng quát hóa hoặc chuyên môn hóa: hãy hướng đến sự chuyên môn hóa. Như một hệ quả tất yếu, cây trạng thái cho thành phần của bạn phải có một parsimony nhất định (mặc dù vậy, bạn có thể phá vỡ quy tắc này một cách nhã nhặn nếu bạn đang tạo ra một sản phẩm mới có thương hiệu).

Dù sao đây là cách bạn làm điều đó. Tương tự như câu trả lời (được chấp nhận) của Ben ở trên, nhưng như thế này:

this.setState(this.getInitialState());

Ngoài ra (như Ben cũng đã nói) để thiết lập lại "trạng thái trình duyệt", bạn cần xóa nút DOM đó. Khai thác sức mạnh của vdom và sử dụng một giá keyđỡ mới cho thành phần đó. Kết xuất mới sẽ thay thế bán buôn thành phần đó.

Tham khảo: https://facebook.github.io/react/docs/component-api.html#replacestate


2
Điều này sẽ không hoạt động nếu trạng thái hiện tại bao gồm bất kỳ thuộc tính nào không ở trạng thái ban đầu. Mặc dù tôi không tin rằng đó là một "trạng thái" tuyệt vời của sự việc, trừ khi bạn có thể ngăn chặn bằng cách nào đó, tôi muốn tránh sự đổ vỡ đáng ngạc nhiên. Tôi đồng ý với việc đặt lại bị lỗi trong một số trường hợp, nhưng không phải là đặt lại làm hỏng trạng thái một cách tinh vi.
Eamon Nerbonne

Không chắc tôi làm theo. Bạn đang nói điều này không tương đương với this.replaceState? Cuz nó là như vậy.
wle8300,

1
@ williamle8300 Chúng sẽ không tương đương nếu một thuộc tính mới được thêm vào trạng thái ở đâu đó trong vòng đời thành phần giữa các lần gọi tới getInitialState()(giả sử trong trình xử lý onClick). Trong trường hợp này, thuộc tính mới đó sẽ vẫn tồn tại sau ngày thứ 2 getInitialState().
Graham

@Graham Tôi tin rằng việc đưa trạng thái mới vào một thành phần chưa được khai báo trong đó là một phương pháp không tốt getInitialState. Giống như khai báo tất cả các biến của bạn trong một Hàm JS ở đầu hàm. Lưu ý bên lề: Giải pháp của Ben Alpert gần giống với giải pháp của tôi ... và anh ấy là người bảo trì React chính thức!
wle8300

1
Tôi sợ rằng hàm getInitialState (), và do đó câu trả lời, không được dùng nữa. Một bản cập nhật sẽ rất tốt.
Martin R.

8

Thêm keythuộc tính vào phần tử mà bạn cần khởi động lại, sẽ tải lại thuộc tính đó mỗi khi propshoặc stateliên kết với phần tử thay đổi.

key = {new Date (). getTime ()}

Đây là một ví dụ:

render() {
  const items = (this.props.resources) || [];
  const totalNumberOfItems = (this.props.resources.noOfItems) || 0;

  return (
    <div className="items-container">
      <PaginationContainer
        key={new Date().getTime()}
        totalNumberOfItems={totalNumberOfItems}
        items={items}
        onPageChange={this.onPageChange}
      />
    </div>
  );
}

1
Hoặc bạn có thể thêm một biến bộ đếm số nguyên đơn giản làm khóa
tối giản
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.