React logo

useRef

ืžื” ื–ื” useRef?

useRef ืžื—ื–ื™ืจ ืื•ื‘ื™ื™ืงื˜ ืขื ืฉื“ื” current ืฉื ื™ืชืŸ ืœืฉื ื•ืชื• ืžื‘ืœื™ ืœื’ืจื•ื ืœืจื™ื ื“ื•ืจ. ืžืฉืžืฉ ืœ:

  • ื’ื™ืฉื” ืœืืœืžื ื˜ื™ื ื‘-DOM (ืœืžืฉืœ ืคื•ืงื•ืก ืœืงืœื˜).
  • ืฉืžื™ืจื” ืขืœ ืขืจื›ื™ื ืžืชืžืฉื›ื™ื ื‘ื™ืŸ ืจื™ื ื“ื•ืจื™ื (ื˜ื™ื™ืžืจื™ื, ืžื•ื ื™ื, previous value).
  • ื“ื™ืœื•ื’ ืขืœ ื”ืจื™ืฆื” ื”ืจืืฉื•ื ื” ืฉืœ ืืคืงื˜ื™ื/ื”ื‘ื—ื ื” ื‘ื™ืŸ mount ืœ-update.

ืชื•ื›ืŸ ืขื ื™ื™ื ื™ื

  1. ref ืœ-DOM: ืคื•ืงื•ืก ื•ืฉื™ืžื•ืฉื™ื
  2. ืขืจื›ื™ื ืžืชืžืฉื›ื™ื ืœืœื ืจื™ื ื“ื•ืจ
  3. Previous Value ืขื useRef
  4. ืžื“ื™ื“ืช ืืœืžื ื˜ DOM
  5. ื ื™ื”ื•ืœ ื˜ื™ื™ืžืจื™ื/ืื™ื ื˜ืจื•ื•ืœื™ื
  6. ืงื•ื“ ื‘ืกื™ืก ืฉืงื™ื‘ืœืช (UseRefBasics)
  7. ื˜ื™ืคื™ื ื—ืฉื•ื‘ื™ื
  8. SEO: ืงื™ืฉื•ืจื™ื ื—ื™ืฆื•ื ื™ื™ื ื ื›ื•ืŸ

1) ref ืœ-DOM

ื“ื•ื’ืžื”: ืคื•ืงื•ืก ืื•ื˜ื•ืžื˜ื™ ืขืœ ืฉื“ื” ืงืœื˜ ื‘ืขืช mount.

const inputRef = useRef(null);
useEffect(() => {
  inputRef.current?.focus();
}, []);
return <input ref={inputRef} />;
ื“ื•ื’ืžื” ื—ื™ื”

2) ืขืจื›ื™ื ืžืชืžืฉื›ื™ื ืœืœื ืจื™ื ื“ื•ืจ

ืฉื™ื ื•ื™ ref.current ืœื ืžืคืขื™ืœ ืจื™ื ื“ื•ืจ, ืœื›ืŸ ืžืชืื™ื ืœื˜ื™ื™ืžืจื™ื, ืžื•ื ื™ื ืคื ื™ืžื™ื™ื ืื• ืฉืžื™ืจื” ืขืœ ืื•ื‘ื™ื™ืงื˜ื™ื ื‘ื™ืŸ ืจื™ื ื“ื•ืจื™ื.

const ref = useRef(0);
ref.current += 1; // ืœื ื™ื’ืจื•ื ืœืจื™ื ื“ื•ืจ
ื“ื•ื’ืžื” ื—ื™ื”
renders: 0
counterRef.current: 0

ืขืจืš ื‘ืชื•ืš useRef ืื™ื ื• ืžืคืขื™ืœ ืจื™ื ื“ื•ืจ; ื˜ื•ื‘ ืœืฉืžื™ืจืช ืกืคื™ืจื•ืช, ืžื–ื”ื™ื ื•ื˜ื™ื™ืžืจื™ื.

3) Previous Value ืขื useRef

ืฉื•ืžืจื™ื ืืช ื”ืขืจืš ื”ืงื•ื“ื ื‘ื›ืœ ืฉื™ื ื•ื™, ืœืœื ืจื™ื ื“ื•ืจ ื ื•ืกืฃ.

const [value, setValue] = useState(0);
const prevRef = useRef(value);
useEffect(() => { prevRef.current = value; }, [value]);
ื“ื•ื’ืžื” ื—ื™ื”
value: 0
prev: 0

4) ืžื“ื™ื“ืช ืืœืžื ื˜ DOM

ืžืชืื™ื ืœืžื“ื™ื“ื•ืช, ืžื™ืงื•ืžื™ื ื•ึพlayout.

const boxRef = useRef(null);
const [rect, setRect] = useState({});
useEffect(() => {
  const el = boxRef.current;
  if (!el) return;
  const update = () => setRect(el.getBoundingClientRect());
  update();
  const ro = new ResizeObserver(update);
  ro.observe(el);
  return () => ro.disconnect();
}, []);
ื“ื•ื’ืžื” ื—ื™ื”
ืฉื ื” ืจื•ื—ื‘ ื—ืœื•ืŸ/ื˜ืงืกื˜ ื›ื“ื™ ืœืจืื•ืช ืขื“ื›ื•ืŸ.
width: 0px, height: 0px

5) ื ื™ื”ื•ืœ ืื™ื ื˜ืจื•ื•ืœื™ื ืขื ref

ืฉื•ืžืจื™ื ืืช ืžื–ื”ื” ื”ืื™ื ื˜ืจื•ื•ืœ ื‘ึพref ื›ื“ื™ ืœืขืฆื•ืจ/ืœื”ืคืขื™ืœ ื•ืœื”ื™ืžื ืข ืžื”ื—ื–ืงื” ื‘ึพstate.

const idRef = useRef(null);
const start = () => {
  if (idRef.current) return;
  idRef.current = setInterval(doSomething, 1000);
};
const stop = () => {
  clearInterval(idRef.current);
  idRef.current = null;
};
ื“ื•ื’ืžื” ื—ื™ื”
ticks: 0

6) UseRefBasics โ€” ื”ืงื•ื“ ืฉืœืš (ืขื ื”ืขืจื•ืช)

import { useEffect, useRef, useState } from 'react';

const UseRefBasics = () => {
  const [value, setValue] = useState(0);
  const refContainer = useRef(null);
  const isMounted = useRef(false);

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log(refContainer.current);         // ืžืฆื‘ื™ืข ืœืงืœื˜
    const name = refContainer.current.value;   // ืงืจื™ืืช ืขืจืš ืžื”- input
    console.log(name);
  };

  useEffect(() => {
    // ื”ืคื•ืงื•ืก ืขืœ ื”ืงืœื˜ ื‘ืขืช mount
    refContainer.current.focus();
  }, []);

  useEffect(() => {
    // ื“ื™ืœื•ื’ ืขืœ ื”ืจื™ืฆื” ื”ืจืืฉื•ื ื”
    if (!isMounted.current) {
      isMounted.current = true;
      return;
    }
    console.log('re-render'); // ื™ืจื•ืฅ ืจืง ื‘ืขื“ื›ื•ื ื™ื
  }, [value]);

  return (
    <div>
      <form className='form' onSubmit={handleSubmit}>
        <div className='form-row'>
          <label htmlFor='name' className='form-label'>Name</label>
          <input type='text' id='name' ref={refContainer} className='form-input' />
        </div>
        <button type='submit' className='btn btn-block'>submit</button>
      </form>

      <h1>value : {value}</h1>
      <button onClick={() => setValue(value + 1)} className='btn'>increase</button>
    </div>
  );
};

export default UseRefBasics;

7) ื˜ื™ืคื™ื ื•ื“ื’ืฉื™ื

  • ืฉื™ื ื•ื™ ref.current ืœื ืžืจื ื“ืจ โ€” ื˜ื•ื‘ ืœืฉืžื™ืจืช ืžื™ื“ืข ืฆื“ื“ื™ (ื˜ื™ื™ืžืจื™ื, previous value, ื“ื’ืœื™ื).
  • ืืœ ืชื›ืชื‘ื• ืœึพref.current ื‘ืชื•ืš ื”ืจื™ื ื“ื•ืจ ืื ื”ืขืจืš ืžืฉืคื™ืข ืขืœ ื”ึพUI; ื‘ืฉื‘ื™ืœ ื–ื” ื™ืฉ state.
  • ืœืฉื™ืœื•ื‘ ืขื useEffect: ื ื™ืชืŸ ืœืฉืžื•ืจ ื“ื’ืœื™ื ื›ืžื• isMounted.current ื›ื“ื™ ืœื“ืœื’ ืขืœ ื”ืจื™ืฆื” ื”ืจืืฉื•ื ื”.
  • ื‘ืžื“ื™ื“ื•ืช DOM ื”ืขื“ื™ืคื• ResizeObserver ืขืœ ืžืื–ื™ื ื™ resize ื’ืœื•ื‘ืœื™ื™ื.

8) SEO: ืงื™ืฉื•ืจื™ื ื—ื™ืฆื•ื ื™ื™ื (Best Practices)

  • ื”ืฉืชืžืฉื• ื‘ืขื•ื’ืŸ ืขื ื˜ืงืกื˜ ืชื™ืื•ืจื™ (Anchor Text) ืฉืžืกื‘ื™ืจ ืžื” ื™ืฉ ื‘ืงื™ืฉื•ืจ โ€” ื–ื” ืขื•ื–ืจ ืœืžื ื•ืขื™ ื—ื™ืคื•ืฉ ื•ืœื”ื ื’ืฉื”.
  • ืœื™ืขื“ ื—ื™ืฆื•ื ื™ ืคืชื—ื• ื‘ื˜ืื‘ ื—ื“ืฉ ื‘ืืžืฆืขื•ืช target="_blank" + ื”ื•ืกื™ืคื• rel="noopener noreferrer" ืœื‘ื˜ื™ื—ื•ืช.
  • ืื ื”ืงื™ืฉื•ืจ ืžืžื•ืชื’/ืจืฉืžื™, ื”ื–ื›ื™ืจื• ืืช ืฉื ื”ืžืงื•ืจ (MDN/React Docs) ื‘ื˜ืงืกื˜.
// ื“ื•ื’ืžืช ืงื™ืฉื•ืจื™ื ื—ื™ืฆื•ื ื™ื™ื ื™ื“ื™ื“ื•ืชื™ื™ื ืœ-SEO:
<p>
  ืงืจืื• ืืช
  {' '}
  <a
    href="https://react.dev/reference/react/useRef"
    target="_blank"
    rel="noopener noreferrer"
  >
    ื”ืชื™ืขื•ื“ ื”ืจืฉืžื™ ืฉืœ React ืขืœ useRef
  </a>
  {' '}ื•ื’ื ืืช
  {' '}
  <a
    href="https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver"
    target="_blank"
    rel="noopener noreferrer"
  >
    ืžื“ืจื™ืš MDN ืขืœ ResizeObserver
  </a>
  .
</p>

๐Ÿš€ ืกื™ื›ื•ื

useRef ื”ื•ื ื›ืœื™ ื’ืžื™ืฉ ืœืฉืžื™ืจืช ืžืฆื‘ื™ืขื™ DOM ื•ืขืจื›ื™ื ืžืชืžืฉื›ื™ื ืœืœื ืจื™ื ื“ื•ืจ. ื”ืฉืชืžืฉ ื‘ื• ืœืžื“ื™ื“ื•ืช, ืคื•ืงื•ืก, ื˜ื™ื™ืžืจื™ื ื•ืœืฉืœื™ื˜ื” ื‘ืžื—ื–ื•ืจ-ื—ื™ื™ื ื™ื—ื“ ืขื useEffect.