React

[React] Hooks - useRef

wwxs 2024. 8. 31. 21:14

useRef

: use + Reference(참조)

  • 변경 가능한 참조 객체를 생성할 수 있는 기능(훅)

사용 목적

  • DOM 요소에 직접적으로 접근하고 조작
  • 컴포넌트가 재렌더링될 때도 값이 유지되는 변수 관리
  • 이전 상태를 기억 (렌더링 사이에 지속되는 값을 유지)

기본 문법

const refContainer = useRef(initialValue)

  • initialValue: 참조 객체의 초기값
  • refContainer.current: 저장된 현재 값에 접근

추가내용

더보기

 useRef는 객체를 반환

  • 해당 객체에는 current라는 속성이 존재
  • 컴포넌트의 재렌더링에도 값이 유지

(예제 코드)

더보기
export default function UseRef01() {
  const [text, setText] = useState<string>('');

  const lengthRef = useRef(0);

  // let lengthData = 0;
  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setText(e.target.value);
    lengthRef.current = e.target.value.length;
    // lengthData = e.target.value.length;
  }
  return (
    <div>
      <h4>현재 텍스트 길이 측정 예제</h4>
      <input type="text" value={text} onChange={handleInputChange} />
      <p>Text길이: {lengthRef.current}</p>
      {/* <p>{lengthData}</p> */}
    </div>
  )
}

 

useRef를 사용한 DOM 요소 참조

  • 컴포넌트가 재렌더링 되더라도 동일한 참조값을 유지
  • 특정 DOM 요소에 접근하고 조작
더보기
export default function UseRef02() {
  const [count, setCount] = useState<number>(0);
  const inputRef = useRef<HTMLInputElement>(null);
  const prevCountRef = useRef<number>(0)

  const handleButtonFocus = () => {
    // 'current'는 참조하는 DOM 요소를 나타냄
    if (inputRef.current) {
      // .focus(): DOM 요소를 활성화
      inputRef.current.focus();
    }
  };

  const incrementCount = () => {
    setCount((prevcount) => {
      prevCountRef.current = prevcount;
      return prevcount + 1;
    });
  };
  return (
    <div>
      <input type="text" ref={inputRef} />
      <button onClick={handleButtonFocus}>Focus the input</button>
      <hr />

      <p>현재 카운트: {count}</p>
      <p>이전 카운트: {prevCountRef.current}</p>
      <button onClick={incrementCount}>증가</button>
    </div>
  );
}

 

 

배열 렌더링(추가, 조회, 수정, 삭제 - CRUD)

  • 해당 과정에서 배열 내부의 각 요소를 구분 지을 id 값이 필요

(예제 : 장바구니 구현)

더보기
// 장바구니의 타입 정의
interface IItem {
  id: number;
  name: string;
  amount: number;
}

// 기존 장바구니 목록
const initialItems: IItem[] = [
  { id: 1, name: "사과", amount: 2 },
  { id: 2, name: "칸쵸", amount: 3 },
  { id: 3, name: "우유", amount: 1 },
];

//# 자식 컴포넌트
// : 장바구니 항목 1개
// >> 부모로 부터 각 아이템을 인자로 받아 하나의 장바구니 항목을 생성

interface IItemProps {
  item: IItem;
}

// function Item({ item }: { item: IItem }) {}
function Item({ item }: IItemProps) {
  return (
    <div>
      <p>
        <b>{item.name}</b>
        amount: {item.amount}
      </p>
    </div>
  );
}

//! useRef를 사용한 고유한 id값 생성

//# '각 아이템'을 보여주는 컴포넌트
// : 수정, 삭제 기능 포함

// 컴포넌트 props 타입 정의
interface ItemComponentProps {
  item: IItem; // id, name, amount

  onRemove: (id: number) => void;
  onUpdate: (id: number, amount: number) => void;
}

const ItemComponent = ({ item, onRemove, onUpdate }: ItemComponentProps) => {
  return (
    <div>
      <strong>{item.name}</strong>
      <input
        type="number"
        value={item.amount}
        onChange={(e) => onUpdate(item.id, Number(e.target.value))}
      />
      <button onClick={() => onRemove(item.id)}>삭제</button>
    </div>
  );
};

//# 부모 컴포넌트
export default function UseRef03() {
  const [items, setItems] = useState<IItem[]>(initialItems);
  // useRef
  // >> 컴포넌트가 리렌더링 되더라도 해당 값은 유지
  // const 참조값을 담을 변수 = useRef<데이터의타입>(초기값);
  const nextId = useRef<number>(4);


  //? 새로운 아이템을 생성하는 함수
  const handleCreateItem = (name: string, amount: number) => {
    const newItem = {
      id: nextId.current,
      name,
      amount,
    };

    setItems([...items, newItem]);
    nextId.current ++;
  };

  //? id와 수량을 전달받아 데이터를 수정하는 함수
  const handleUpdateAmount = (id: number, amount: number) => {
    setItems(
      items.map((item) => (item.id === id ? { ...item, amount } : item))
    );
  };

  //? id값을 전달 받아 삭제하고자 하는 요소를 filtering하는 함수
  const handleRemove = (id: number) => {
    setItems(items.filter((item) => item.id !== id));
  };

  return (
    <div>
      {/* 
        <Item item={initialItems[0]} />
        <Item item={initialItems[1]} />
        <Item item={initialItems[2]} /> 
      */}
      {/* 
        {initialItems.map((item, index) => (
          // map과 filter 사용 시 생성되는 컴포넌트 또는 요소에는
          // , 각각을 구분할 수 있는 key값을 전달!
          <Item item={item} key={index} />
        ))} 
      */}
      {initialItems.map((item) => (
        // map과 filter 사용 시 생성되는 컴포넌트 또는 요소에는
        // , 각각을 구분할 수 있는 key값을 전달!

        // 배열 안의 객체 데이터는 각 데이터를 구분할 수 있는
        // : 고유하고 변화되지 않는 id값 사용을 권장
        <Item item={item} key={item.id} />
      ))}

      <hr />
      <button onClick={() => handleCreateItem("새로운 항목", 1)}>
        새 항목 추가
      </button>
      <>
        {items.map((item) => (
          <div key={item.id}>
            <ItemComponent
              item={item}
              onRemove={handleRemove}
              onUpdate={handleUpdateAmount}
            />
          </div>
        ))}
      </>
    </div>
  );
}

'React' 카테고리의 다른 글

[React] Hooks - useCallback + useMemo  (0) 2024.09.06
[React] Hooks - useEffect  (0) 2024.08.31
[React] Hooks - useState  (0) 2024.08.31
[React] Handler  (0) 2024.08.29
[React] Rendering  (0) 2024.08.29