+5

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>
    </>
  )
}

Demo: https://codesandbox.io/s/useimperativehandle-5zq3dm


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.