# What is Ref ?

![Đây chỉ là hình minh họa](/files/-MCaKPDzrh88YmjnY_yG)

&#x20;**React refs** là một tính năng hữu ích, nó là cách mà chúng ta có thể để tham chiếu một element trong DOM hoặc từ một class component con đến component cha. Điều này cho phép chúng ta đọc và chỉnh sửa các element đó.

Cách giải thích dễ hiểu nhất về React Refs là tưởng tượng nó là một cây cầu. Khi một element được gán vào một ref nó sẽ cho phép chúng ta sửa đổi cũng như truy cập vào element đó ngay lập tức và không cần sử dụng đến props hay state để component re-render. Nó giống cho phép việc can thiệp vào DOM như trong Javascript DOM

```javascript
document.getElementsByTagName('h1').innerHTML = 'Freetuts.net'
```

&#x20;Chúng ta có thể can thiệp trực tiếp vào DOM qua refs mà không cần thông qua việc render. Mặc dù đây là cách để can thiệp vào DOM thuận tiện mà không cần phải sử dụng đến state, props nhưng điều này React không khuyến khích. Bởi khi các DOM bị thay đổi thì nó sẽ ảnh hưởng một phần nào đó đến quá trình render các component. Các bạn nên sử dụng **React refs** để can thiệp vào DOM trong trường hợp cần thiết.

### Forwarding Refs

**Forwarding Refs** là một kỹ thuật để tự động chuyển một ref từ một component tới component con, cho phép component cha có thể tham chiếu tới các element của component con để đọc và chỉnh sửa nó.

React cung cấp cho chúng ta một cách thức để thực hiện việc chuyển tiếp một ref, chúng ta sẽ bao component con trong `React.forwardRef()`, ở đây mình có ví dụ:

```jsx
//Component Con
const MyInput = React.forwardRef((props, ref) => {
   return(<input name={props.name} ref={ref} />);
});
// Component Cha
const MyComponent = () => {
   let ref = React.createRef();
   return (
     <MyInput
       name="email"
       ref={ref}
     />
   );
}
```

&#x20;Ví dụ bên trên mình đã sử dụng `React.forwardRef()`, ở đây nó cung cấp cho chúng ta 2 tham số lần lượt là `props` và `refs`, cho chúng ta nhận về giá trị của **props** và **refs** từ component cha.

### Một số trường hợp dùng `refs` <a href="#mot-so-truong-hop-dung-refs-2" id="mot-so-truong-hop-dung-refs-2"></a>

* Control focus, get text của DOM element, get state value(play/pause/timeline) của media playback,... nói chung là dùng trong những trường hợp các data này không cần đưa vào `state` của component.
* Trigger các transitions, animations: sử dụng `refs` khi một element cần trigger animation/transition của một element khác
* Tích hợp với các Third-party DOM libraries

### Các ví dụ

#### Điều khiển focus của input: <a href="#dieu-khien-focus-cua-input-5" id="dieu-khien-focus-cua-input-5"></a>

Ở ví dụ này, chúng ta sẽ sử dụng `userRef` để tham chiếu tới input element, sau đó sẽ thực hiện focus input khi click button

```jsx
import React, { useRef } from "react";

function App() {
  const inputEl = useRef(null);

  const onButtonClick = () => {
    inputEl.current.focus();
  };

  return (
    <div className="App">
      <h2>Use refs to control focus</h2>
      <input ref={inputEl} />
      <button onClick={onButtonClick}>Focus the input</button>
    </div>
  );
}
```

Demo: <https://codesandbox.io/s/dawn-thunder-w9hur>

#### Set/Get giá trị trước đó của state: <a href="#setget-gia-tri-truoc-do-cua-state-6" id="setget-gia-tri-truoc-do-cua-state-6"></a>

Ở ví dụ này; sẽ có 1 input, nhập một vài ký tự và thực hiện `blur` input đó, chúng ta sẽ check xem `previous value`, `current value` sau mỗi lần blur input (case này trong thực tế là: nếu sau mỗi lần blur mà giá trị trước và sau khi blur có thay đổi thì thực hiện call api, ngược lại nếu không thay đổi thì không làm gì cả)

```jsx
import React, { useRef, useState } from "react";

function App() {
  const prevValue = useRef("");
  const [value, setValue] = useState("");

  const onInputChange = e => {
    setValue(e.target.value);
  };

  const onInputBlur = () => {
    console.log(`Previous value: ${prevValue.current}`);
    console.log(`Current value: ${value}`);
    prevValue.current = value;
  };

  return (
    <div className="App">
      <h2>Use refs to set/get previous state's value</h2>
      <input value={value} onBlur={onInputBlur} onChange={onInputChange} />
      <div>Type something, blur input and check result in console.log</div>
    </div>
  );
}
```

Demo: <https://codesandbox.io/s/hungry-glade-d7mjb>

Sau khi hiểu về `useRef` ở ví dụ trên, chúng ta sẽ hay gặp 1 trường hợp thực tế như sau: sau khi input data vào các field trên màn hình(route A) sau đó điều hướng sang route B, lúc này ta sẽ cần lưu các data trên màn hình vào `redux store` như sau:

```jsx
import React, { useState, useEffect, useRef } from "react";

function App() {
  const onScreenData = useRef({});
  const [inputs, setInputs] = useState({});

  const onInputChange = e => {
    const [name, value] = e.target;
    const updatedInputs = { ...inputs, [name]: value };
    setInputs(updatedInputs);
    onScreenData.current = updatedInputs;
  };

  useEffect(
    () => () => {
      saveScreenData(onScreenData.current);
    },
    []
  );

  return (
    <div>
      <h2>Use refs to get the latest inputs value</h2>
      <label>Title: </label>
      <input name="title" value={inputs.title || ""} onChange={onInputChange} />
      <label>Note: </label>
      <input name="note" value={inputs.note || ""} onChange={onInputChange} />
    </div>
  );
}

const saveScreenData = data => {
  // Save data to redux store
};
```

Demo: <https://codesandbox.io/s/distracted-banzai-3hrwb>

#### Control animation: <a href="#control-animation-7" id="control-animation-7"></a>

Chúng ta sử dụng `useRef` để get tham chiếu đến `DOM element` và thực hiện trigger animation

```jsx
import React, { useRef, useEffect } from "react";
import { TweenMax } from "gsap";

function App() {
  const circle = useRef(null);

  useEffect(() => {
    TweenMax.fromTo(
      [circle.current],
      0.5,
      { y: 18 },
      { y: -18, yoyo: true, repeat: -1 }
    );
  }, []);

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <svg viewBox="0 0 150 33.2" width="180" height="150">
        <circle ref={circle} cx="16.1" cy="16.6" r="16.1" fill="#527abd" />
      </svg>
    </div>
  );
}
```

&#x20;Demo: <https://codesandbox.io/s/sleepy-mendel-lc8kz>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://pea-story.gitbook.io/pexpa/knowledge/reactjs/what-is-ref.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
