Chuyển tiếp Refs (references) là một kỹ thuật tự động chuyển một ref từ một component cha đến component con của nó để truy cập đến tất cả thuộc tính, action… của element trong component con.
Ref là gì?
Trong React, ref là một thuộc tính của một thẻ hoặc một element đại diện cho chính nó.
Ref cho phép chúng ta truy cập đến DOM node hoặc React element khi đã được render thành công (mounted).
Trong Javascript, chúng ta làm việc với DOM elements bằng cách gọi document.getElementById() hoặc các cú pháp selector khác. Với Ref trong React, chúng ta không cần làm vậy. Thuộc tính ref sẽ tham chiếu trực tiếp đến element ta cần dùng.
Ví dụ:
<input type="text" ref={textInput} />
Ref nhận vào một biến hoặc function. Nếu là function, nó sẽ được thực thi khi element này được mount.
Ví dụ khác:
<button ref={(element) => console.log(element)}>Send</button>
Kết quả element được ref tham chiếu đến:
Khởi tạo ref bằng React.createRef()
Chúng ta sử dụng API React.createRef() để khởi tạo một ref gắn vào các elements của React thông qua thuộc tính ref.
Ta có thể khai báo nó trong hàm constructor() như sau:
import React from "react";
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}
render() {
return <input type="text" ref={this.inputRef} />;
}
componentDidMount() {
this.inputRef.current.focus();
}
}
Luồng chạy như sau:
- React.createRef() tạo ra một React ref tham chiếu đến input element, mặc định là giá trị null.
- Ở element input ta gán ref={this.inputRef} để truy cập đến tất cả behavior của input element.
- Sau khi render element thành công, ta tham chiếu đến action focus() của input thông qua this.input đã khai báo trước đó.
- Kết quả: trỏ chuột sẽ tự động trỏ vào trong thẻ input sau khi chúng ta render thành công.
forwardRef() là gì?
Giới thiệu vềforwardRef()
forwardRef() là một phương thức cho phép các component cha truyền một ref (tham chiếu) xuống các component con của chúng.
Nói cách khác, forwardRef() giúp chuyển tiếp quyền truy cập đến các element trong component con đến component cha. Vì thế các component cha có thể truy cập đến các element bên trong các component con được forwardRef.
Ví dụ, một máy tính đặt ở nhà và chúng ta muốn điều khiển nó từ công ty, chúng ta phải tạo một kết nối (ref) để truy cập vào để làm việc, nếu không có nó thì chúng ta không thể làm gì cả. Tương tự, để component cha có thể truy cập đến các element của component con, chúng ta sử dụng một kết nối là forwardRef().
Cú pháp:
forwardRef() là một hàm chứa 2 tham số props và ref. Kết quả trả về là một JSX element.
Cách sử dụng forwardRef()
Ví dụ, sử dụng forwardRef() để focus đến input của component con từ component cha:
Tạo component con EmailInput:
const EmailInput = (props) => {
return <input {...props} type="email" className="AppEmailInput" />;
};
Tạo component cha App, với ref được khởi tạo bởi API React.createRef() và một button có sự kiện click để fucus vào component con:
class App extends React.Component {
constructor(props) {
super(props);
this.emailRef = React.createRef();
}
onClickButton() {
this.emailRef.current.focus();
}
render() {
return (
<div>
<EmailInput />
<button onClick={() => this.onClickButton()}>
Click me to focus email
</button>
</div>
);
}
}
export default App;
Lúc này, component con EmailInput của chúng ta chưa sử dụng forwardRef. Do đó, component cha không thể truy cập đến behavior của nó, giá trị ref hiện tại chỉ là null.
Để truy cập đến element của component con EmailInput, ta thêm forwardRef() như sau, React chuyển ref của App đến EmailInput thông qua đối số thứ 2 (ref) của hàm forwardRef():
const EmailInput = React.forwardRef((props, ref) => {
return <input ref={ref} {...props} type="email" className="AppEmailInput" />;
});
Ở component App, ta sẽ thêm thuộc tính ref để lấy quyền truy cập vào element của component con:
<EmailInput ref={this.emailRef} />
Lúc này, giá trị this.emailRef sẽ trỏ đến DOM node input và lưu tất cả các thuộc tính và action của input vào React ref để App có thể sử dụng:
Lưu ý
Đối số thứ 2 ref chỉ tồn tại khi bọc một component với hàm React.forwardRef(). Các function hoặc class component thông thường không nhận được đối số ref và nó cũng không có sẵn trong các props.
Nếu chúng ta truyền ref từ component cha mà component con không sử dụng React.forwardRef() thì hệ thống sẽ phát cảnh báo trong tab console như sau:
Sử dụng forwardRef() trong HOC
Trong phần lưu ý trên, component con chỉ nhận ref với đối số thứ 2 khi sử dụng forwardRef(). Nhưng HOC thì không biết được điều đó, bởi vì HOC chỉ nhận các giá trị đầu vào và truyền đi như các props. HOC có thể nhận ref như 1 props nhưng các component con của nó không thể nhận được. Vậy chúng ta nên làm thế nào mới đúng?
Chúng ta không thể sử dụng HOC sau React.forwardRef(), tương đương chúng ta có thể sử dụng HOC trước khi khi forwading ref.
Ví dụ:
Ta tạo một HOC như sau:
function withStatusMessages(WrappedComponent) {
return ({ errorText, successText, ...props }) => {
return (
<>
<WrappedComponent {...props} />
{errorText ? <div className="errorText">{errorText}</div> : null}
{successText ? <div className="successText">{successText}</div> : null}
</>
);
};
}
Tạo thêm một component con từ HOC trên, nhận vào một inputRef như một props:
const Input = withStatusMessages(function Input({
name,
type,
id,
disabled,
inputRef,
...props
}) {
return (
<input
{...props}
name={name}
id={id}
disabled={disabled}
type={type}
ref={inputRef}
/>
);
});
Sau đó, chúng ta mới sử dụng forwarding ref cho component được tạo từ HOC này:
const InputForward = React.forwardRef((props, ref) => {
return <Input {...props} inputRef={ref} />;
});
Kế tiếp, chúng ta có thể sử dụng chúng như bình thường ở component cha:
class App extends React.Component {
constructor(props) {
super(props);
this.emailRef = React.createRef();
this.onClickButton = this.onClickButton.bind(this);
}
onClickButton(event) {
event.preventDefault();
this.emailRef.current.focus();
}
render() {
return (
<div className="App">
<form name="login-form">
<label htmlFor="email">Email</label>
<InputForward
name="email"
type="text"
id="email"
ref={this.emailRef}
/>
<label htmlFor="password">Password</label>
<InputForward name="password" type="password" id="password" />
<button onClick={this.onClickButton}>Login</button>
</form>
</div>
);
}
}
Phía trên là tất cả chia sẻ của Tino Group về forwardRef. Cám ơn các bạn đã ghé thăm bài viết!
Bài viết có tham khảo từ: https://reactjs.org/docs/forwarding-refs.html