Câu trả lời ngắn:
React đảm bảo rằng các ref được đặt trước componentDidMount
hoặc componentDidUpdate
hook. Nhưng chỉ dành cho trẻ em thực sự được hiển thị .
componentDidMount() {
}
componentDidUpdate() {
}
render() {
return <div ref={/* ... */} />;
}
Lưu ý điều này không có nghĩa là “React luôn đặt tất cả các ref trước khi các hook này chạy”.
Hãy xem xét một số ví dụ mà refs không được thiết lập.
Refs không được thiết lập cho các phần tử không được hiển thị
React sẽ chỉ gọi các lệnh gọi lại ref cho các phần tử mà bạn thực sự đã trả về từ kết xuất .
Điều này có nghĩa là nếu mã của bạn trông giống như
render() {
if (this.state.isLoading) {
return <h1>Loading</h1>;
}
return <div ref={this._setRef} />;
}
và ban đầu this.state.isLoading
là true
, bạn nên không mong đợi this._setRef
để được gọi trước khi componentDidMount
.
Điều này sẽ có ý nghĩa: nếu kết xuất đầu tiên của bạn được trả lại <h1>Loading</h1>
, không có cách nào để React biết rằng trong một số điều kiện khác, nó trả về một thứ khác cần được đính kèm tham chiếu. Ngoài ra còn có gì để thiết lập các ref để: các <div>
yếu tố không được tạo ra bởi vì các render()
phương pháp nói nó không nên được trả lại.
Vì vậy, với ví dụ này, chỉ componentDidMount
sẽ cháy. Tuy nhiên, khi this.state.loading
thay đổi thànhfalse
, bạn sẽ thấy this._setRef
đính kèm trước, sau đó componentDidUpdate
sẽ kích hoạt.
Chú ý các thành phần khác
Lưu ý rằng nếu bạn chuyển các phần tử con có tham chiếu xuống các thành phần khác, có khả năng chúng đang làm điều gì đó ngăn cản việc hiển thị (và gây ra sự cố).
Ví dụ, điều này:
<MyPanel>
<div ref={this.setRef} />
</MyPanel>
sẽ không hoạt động nếu MyPanel
không có props.children
trong đầu ra của nó:
function MyPanel(props) {
return <h1>Oops, no refs for you today!</h1>;
}
Một lần nữa, đó không phải là lỗi: React sẽ không có gì để đặt ref thành vì phần tử DOM không được tạo .
Refs không được đặt trước các vòng đời nếu chúng được chuyển đến một ReactDOM.render()
Tương tự như phần trước, nếu bạn chuyển một con có ref cho một thành phần khác, có thể thành phần này có thể làm điều gì đó ngăn cản việc gắn ref không kịp.
Ví dụ: có thể nó không trả về con từ đó render()
, và thay vào đó nó đang gọi ReactDOM.render()
trong một hook vòng đời. Bạn có thể tìm thấy một ví dụ về điều này ở đây . Trong ví dụ đó, chúng tôi kết xuất:
<MyModal>
<div ref={this.setRef} />
</MyModal>
Nhưng MyModal
thực hiện một ReactDOM.render()
cuộc gọi trong phương thức vòng đời của nó componentDidUpdate
:
componentDidUpdate() {
ReactDOM.render(this.props.children, this.targetEl);
}
render() {
return null;
}
Kể từ React 16, các lệnh gọi kết xuất cấp cao nhất như vậy trong một vòng đời sẽ bị trì hoãn cho đến khi các vòng đời chạy cho toàn bộ cây . Điều này sẽ giải thích tại sao bạn không nhìn thấy các tham chiếu được đính kèm trong thời gian.
Giải pháp cho vấn đề này là sử dụng
các cổng thay vì các ReactDOM.render
cuộc gọi lồng nhau :
render() {
return ReactDOM.createPortal(this.props.children, this.targetEl);
}
Bằng cách này, chúng tôi <div>
với một tham chiếu thực sự được bao gồm trong đầu ra kết xuất.
Vì vậy, nếu bạn gặp sự cố này, bạn cần xác minh rằng không có gì giữa thành phần của bạn và tham chiếu có thể trì hoãn việc hiển thị con.
Không sử dụng setState
để lưu trữ giới thiệu
Đảm bảo rằng bạn không sử dụng setState
để lưu trữ lệnh gọi lại ref trong ref, vì nó không đồng bộ và trước khi nó "kết thúc", componentDidMount
sẽ được thực thi trước.
Vẫn là một vấn đề?
Nếu không có mẹo nào ở trên hữu ích, hãy gửi sự cố trong React và chúng tôi sẽ xem xét.
this
từ phạm vi từ vựng bên ngoài lớp của bạn. Cố gắng loại bỏ cú pháp hàm mũi tên cho các phương thức lớp của bạn và xem nó có hữu ích không.