Sơ lược useRef - fowardRef - useImperativeHandle trong ReactJS
1. useRef trong cùng component
- Khi cả input và button đều trong một Component
- Khởi tạo inputRef bằng cách sử dụng hook
useRef
với giá trị ban đầu là null - Gán vào thẻ input thông qua thuộc tính
ref={inputRef}
- Khi click vào button thì set focus vào input
import { useRef } from 'react'
export default function App() {
const inputRef = useRef(null)
const handleClick = () => {
inputRef.current.focus()
}
return (
<>
<input ref={inputRef} placeholder="Search..." />
<button onClick={handleClick}>Set focus</button>
</>
)
}
Demo: https://codesandbox.io/s/useref-simple-yc38mc
2. fowardRef từ component cha -> con
- Chuyển tiếp
fowardRef
từ component cha xuống component con - Tạo
inputRef
tại component cha - Component cha truyền
inputRef
cho component con như bên dưới
import { useRef } from 'react'
import MyInput from './components/MyInput'
export default function App() {
const inputRef = useRef(null)
const handleClick = () => {
inputRef.current.focus()
}
return (
<>
<MyInput ref={inputRef} placeholder='Search...' />
<button onClick={handleClick}>Set Focus</button>
</>
)
}
- Tách input ra thành component con
MyInput
- Dùng
fowardRef
để nhận đầu vào các props vàref
là tham số thứ hai
import { forwardRef } from 'react'
const MyInput = forwardRef((props, ref) => {
const { placeholder, ...otherProps } = props
return <input {...otherProps} ref={ref} placeholder={placeholder} />
})
export default MyInput
Demo: https://codesandbox.io/s/fowardref-p3c8mf
3. fowardRef toàn bộ
- Ở ví dụ 2 khi chúng ta tách input ra thành một component con
- Chúng ta đã public ra ngoài toàn bộ input này cho component cha
- Nên ở component cha có toàn quyền kiểm soát input này
- Điều này có thể gây ra những lỗi tiềm ẩn cho nội tại input đó
- Ví dụ như component cha xóa input đó thì có thể gây lỗi logic bên trong component con
- Ví dụ bên dưới component cha có thể xóa được luôn cả input đấy đi
import { useRef } from 'react'
import MyInput from './components/MyInput'
export default function App() {
const inputRef = useRef(null)
const handleClick = () => {
inputRef.current.remove() // DANGER
}
return (
<>
<MyInput ref={inputRef} placeholder='Search...' />
<button onClick={handleClick}>Remove input</button>
</>
)
}
Demo: https://codesandbox.io/s/fowardref-2-wm5cq5
4. useImperativeHandle
- Để tránh việc public toàn bộ input ta sử dụng
useImperativeHandle
- Chúng ta sẽ chỉ public những gì có thể tương tác với input đó mà thôi
- Tại component con ta sử dụng
inputRef
nội tại của nó - Gán vào thẻ input thông qua thuộc tính
ref={inputRef}
- Sử dụng hook
useImperativeHandle
nhận ref từ component cha - Public method
setFocus
để component cha có thể sử dụng - Component cha chỉ có thể sử dụng method này để tương tác với component con
import { forwardRef, useRef, useImperativeHandle } from 'react'
const MyInput = forwardRef((props, ref) => {
const inputRef = useRef(null)
useImperativeHandle(
ref,
() => ({
setFocus() {
inputRef.current.focus()
}
}),
[]
)
const { placeholder, ...otherProps } = props
return <input {...otherProps} ref={inputRef} placeholder={placeholder} />
})
export default MyInput
import { useRef } from 'react'
import MyInput from './components/MyInput'
export default function App() {
const myInputRef = useRef(null)
const handleClick = () => {
myInputRef.current.setFocus()
}
return (
<>
<MyInput ref={myInputRef} placeholder='Search...' />
<button onClick={handleClick}>Set Focus</button>
</>
)
}
All rights reserved