ReactJS - Refs và DOM

Xin chào các nhà phát triển React tương lai! Hôm nay, chúng ta sẽ cùng khám phá một chủ đề thú vị giúp bạn tương tác trực tiếp với các phần tử DOM trong ứng dụng React của bạn. Hãy chuẩn bị sẵn sàng, vì chúng ta sắp bước vào thế giới của Refs và DOM!

ReactJS - Refs and the DOM

Refs là gì?

Trước khi chúng ta đi vào chi tiết, hãy hiểu Refs là gì. Trong React, "Ref" là viết tắt của "reference". Nó giống như việc bạn đeo một thẻ tên cho một phần tử cụ thể để bạn có thể dễ dàng tìm thấy nó sau này. Hãy tưởng tượng bạn đang ở một buổi tiệc lớn và bạn muốn theo dõi bạn thân của mình. Bạn có thể cho họ đội một mũ đặc biệt hoặc đeo một thẻ tên độc đáo. Đó chính là điều mà Ref làm trong React - nó giúp bạn theo dõi các phần tử cụ thể.

Tại sao chúng ta cần Refs?

Bạn có thể tự hỏi, "Tại sao chúng ta không thể chỉ cần sử dụng JavaScript thông thường để chọn phần tử?" Trong React, chúng ta cố gắng tránh việc trực tiếp manipulates DOM (Document Object Model) vì React có cách hiệu quả riêng để cập nhật giao diện người dùng. Tuy nhiên, có những lúc chúng ta cần bước ra khỏi范式 declarative của React và làm việc trực tiếp với các phần tử DOM. Đây là lúc Refs trở nên hữu ích!

Tạo Refs với createRef()

Hãy bắt đầu bằng cách xem cách chúng ta tạo một Ref trong React. Chúng ta sử dụng một phương thức gọi là createRef().

Định dạng của phương thức createRef

Định dạng của createRef() rất đơn giản:

React.createRef()

Đó là tất cả! Không có tham số, không có phức tạp. Nó trả về một đối tượng đơn giản với một thuộc tính duy nhất: current. Ban đầu, thuộc tính current này được đặt là null.

Hãy xem một ví dụ:

class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}

render() {
return <div ref={this.myRef} />;
}
}

Trong ví dụ này, chúng ta tạo một Ref trong constructor và gán nó cho this.myRef. Sau đó trong phương thức render, chúng ta gắn Ref này vào một phần tử div sử dụng thuộc tính ref.

Áp dụng Ref

Bây giờ chúng ta đã tạo ra Ref của mình, hãy xem cách chúng ta có thể sử dụng nó. Có một vài cách để áp dụng một Ref:

1. Refs trên các phần tử DOM

Cách sử dụng phổ biến nhất là áp dụng một Ref vào một phần tử DOM:

class AutoFocusInput extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}

componentDidMount() {
this.inputRef.current.focus();
}

render() {
return <input ref={this.inputRef} />;
}
}

Trong ví dụ này, chúng ta tạo một Ref cho một phần tử input. Sau khi component được mount, chúng ta sử dụng Ref để tự động聚焦 vào input. Thuộc tính current của Ref cho phép chúng ta truy cập vào phần tử DOM thực tế.

2. Refs trên các component lớp

Bạn cũng có thể sử dụng Refs với các component lớp:

class AutoScrollingList extends React.Component {
constructor(props) {
super(props);
this.listRef = React.createRef();
}

componentDidUpdate() {
const node = this.listRef.current;
node.scrollToItem(0);
}

render() {
return <MyListComponent ref={this.listRef} />;
}
}

Trong trường hợp này, this.listRef.current sẽ chỉ đến instance của class MyListComponent.

3. Refs và các component hàm

Các component hàm không thể được cấp Ref trực tiếp, nhưng bạn có thể sử dụng hàm forwardRef để truyền Ref qua:

const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));

class MyComponent extends React.Component {
constructor(props) {
super(props);
this.buttonRef = React.createRef();
}

render() {
return <FancyButton ref={this.buttonRef}>Nhấn vào tôi!</FancyButton>;
}
}

Trong ví dụ này, FancyButton sử dụng forwardRef để truyền Ref xuống phần tử button thực tế.

Các trường hợp sử dụng createRef

Bây giờ chúng ta đã biết cách tạo và áp dụng Refs, hãy xem một số trường hợp sử dụng phổ biến:

1. Quản lý focus, chọn văn bản hoặc phát lại media

class TextInput extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}

focusTextInput = () => {
this.inputRef.current.focus();
}

render() {
return (
<div>
<input type="text" ref={this.inputRef} />
<button onClick={this.focusTextInput}>Focus vào input</button>
</div>
);
}
}

Component này cho phép chúng ta tự động聚焦 vào input khi nút được nhấn.

2. Kích hoạt các animation bắt buộc

class Animator extends React.Component {
constructor(props) {
super(props);
this.elementRef = React.createRef();
}

animate = () => {
this.elementRef.current.classList.add('animated');
}

render() {
return (
<div>
<div ref={this.elementRef}>Animate tôi!</div>
<button onClick={this.animate}>Bắt đầu Animation</button>
</div>
);
}
}

Ở đây, chúng ta sử dụng Ref để thêm một class CSS vào một phần tử, kích hoạt một animation.

3. Tích hợp với các thư viện DOM thứ ba

class MapComponent extends React.Component {
constructor(props) {
super(props);
this.mapRef = React.createRef();
}

componentDidMount() {
const mapLibrary = new FancyMapLibrary();
mapLibrary.createMap(this.mapRef.current);
}

render() {
return <div ref={this.mapRef} style={{width: '100%', height: '400px'}} />;
}
}

Trong ví dụ này, chúng ta sử dụng Ref để cung cấp cho một thư viện bản đồ thứ ba quyền truy cập vào một node DOM nơi nó có thể vẽ bản đồ.

Kết luận

Refs là một công cụ mạnh mẽ trong React cho phép chúng ta bước ra khỏi范式 declarative khi cần thiết. Chúng cung cấp một cách để truy cập trực tiếp vào các phần tử DOM hoặc các phần tử React. Tuy nhiên, hãy sử dụng Refs một cách审慎. Trong hầu hết các trường hợp, bạn có thể đạt được điều bạn cần thông qua các API declarative của React. Nhưng khi bạn thực sự cần một chút quyền kiểm soát extra, Refs sẽ luôn ở đó để giúp bạn!

Nhớ rằng, với quyền lực lớn đi kèm với trách nhiệm lớn. Sử dụng Refs một cách khôn ngoan, và ứng dụng React của bạn sẽ cảm ơn bạn!

Dưới đây là bảng tóm tắt các phương thức chúng ta đã thảo luận:

Phương thức Mô tả Ví dụ
React.createRef() Tạo một ref object this.myRef = React.createRef();
ref attribute Gắn một ref vào một phần tử React <div ref={this.myRef} />
forwardRef Cho phép các component hàm nhận refs const FancyButton = React.forwardRef((props, ref) => ...)

Chúc các bạn mã code vui vẻ và may mắn với Refs của bạn!

Credits: Image by storyset