What is Ref ?
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
document.getElementsByTagName('h1').innerHTML = 'Freetuts.net'
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ụ:
//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}
/>
);
}
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
refs
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ácTích hợp với các Third-party DOM libraries
Các ví dụ
Điều khiển focus của input:
Ở 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
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:
Ở 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ả)
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:
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:
Chúng ta sử dụng useRef
để get tham chiếu đến DOM element
và thực hiện trigger animation
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>
);
}
Last updated
Was this helpful?