Frontend/React

React 리액트 - useRef() vs useState()

Ayel 2025. 12. 11. 20:00

 

 

useRef() VS useState()

 

 

useState()

: 화면을 업데이트해야하는 '상태'를 저장하는 용도

-> 상태가 바뀌면 화면이 다시 렌더링된다

 

VS

 

useRef()

: 리렌더링 없이 값을 저장하거나 DOM에 접근하는 용도

-> 값이 바뀌어도 화면이 렌더링되지 않는다

 

- 값이 바뀌어도 화면을 바꾸고 싶지 않을 때 사용

- useState()를 남발하면 불필요한 렌더가 계속 일어나기 때문에 성능이 저하된다

-> useRef()가 훨씬 효율적이 될 수 있다

 

- checkBox처럼 화면과 무관한 값을 저장할 때 useRef()를 사용하기 좋다

 

 

Check 유효성 검사

 

 

사용자로부터 ID와 PW를 입력받아 전송
유효성 검사를 통해 ID와 PW과 입력받지 않은 경우 경고창을 띄운다

 

 

import React from 'react';
import { useRef } from 'react';

// 아이디, 비밀번호를 눌렀을 때 유효성 검사
// 순서가 상관이 없어서 배열이다 -> 
// ** 객체는 순서대로 value값이 들어가야 함

const Check = () => {

  const expressionRef = useRef([])
  const formRef = useRef()

  const handleSubmitOnClick = () => {
    for(let input of expressionRef.current){
      if(!input.value){
        console.error(`${input.name}의 값이 없습니다.`)
        alert(`${input.name} 정보를 입력하세요`)
        return;
      }
    }
    // 데이터 전송
    formRef.current.submit()
  }

  return (
    <div>
      <form action="" ref={formRef}>
        <span>ID</span>
        <div><input ref={(el) => expressionRef.current[0] = el} type="text" name="id" /></div>
        <span>PW</span>
        <div><input ref={(el) => expressionRef.current[1] = el} type="text" name="pw" /></div>
        <button type="button" onClick={handleSubmitOnClick}>GO!</button>
      </form>
    </div>
  );
};

export default Check;

 

 

- ref={(el) => expressionRef.current[0] = el}

- [] 배열 사용: 순서 상관 없이 한꺼번에 물어봄

-> 앞/뒤 순서 상관 없이 질문에 대한 답만 받으면 됨

- 콜백함수 사용: 앞에서 값을 받아서 자기의 태그를 그대로 주는 함수

 

 

<결과화면>

 

 

- ID와 PW를 모두 입력한 후 GO!버튼을 누르면 정상적으로 전송됨

 

 

CheckBoxRef

 

 

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

const CheckBoxRef = () => {

  const [hobbies, setHobbies] = useState("");
  const inputRef = useRef([])

  const handleHobbiesOnClick = () => {

    const hobby = inputRef.current
      .filter((checkbox) => checkbox.checked)
      .map((checkbox) => checkbox.value)
      .join(", ")

    setHobbies(hobby)
  }

  return (
    <div>
      <div>
        <label><span>Running</span>
          <input type="checkbox" value="Running" name="hobby" 
          ref={(el) => inputRef.current[0] = el} 
          />
        </label>
        <label><span>Reading books</span>
          <input type="checkbox" value="Reading books" name="hobby" 
          ref={(el) => inputRef.current[1] = el} 
          />
        </label>
        <label><span>Belly Dancing</span>
          <input type="checkbox" value="Belly Dancing" name="hobby" 
          ref={(el) => inputRef.current[2] = el} 
          />
        </label>
        <button onClick={handleHobbiesOnClick} type="button">CLICK</button>
      </div>
      <p>{hobbies}</p>
    </div>
  );
};

export default CheckBoxRef;

 

 

<결과화면>

 

- 체크박스에 체크한 후 CLICK 버튼을 누르면

아래쪽에 체크한 항목이 출력된다

- 다시 체크를 해제하고 버튼을 누르면 그대로 반영된다

 

 

CheckBoxRef2

 

 

사용자가 체크박스를 클릭하면 체크한 취미를 화면에 실시간으로 보여준다
사용자가 체크박스를 해제하면 체크한 취미도 화면에서 사라진다.

 

 

import { useRef, useState } from 'react';

const CheckBoxRef02 = () => {

  const [hobbies, setHobbies] = useState("");
  const inputRef = useRef([])

  const handleHobbiesOnChange = () => {
    const hobby = inputRef.current
      .filter((checkbox) => checkbox.checked)
      .map((checkbox) => checkbox.value)
      .join(", ")

    setHobbies(hobby)
  } 

  return (
    <div>
      <div>
        <label>
          <span>Running</span>
          <input type="checkbox" onChange={handleHobbiesOnChange} value="Running" name="hobby" 
          ref={(el) => inputRef.current[0] = el} 
          />
        </label>
        <label>
          <span>Reading books</span>
          <input type="checkbox" onChange={handleHobbiesOnChange} value="Reading books" name="hobby" 
          ref={(el) => inputRef.current[1] = el} 
          />
        </label>
        <label>
          <span>Belly Dancing</span>
          <input type="checkbox" onChange={handleHobbiesOnChange} value="Belly Dancing" name="hobby" 
          ref={(el) => inputRef.current[2] = el} 
          />
        </label>
      </div>
      <p>{hobbies}</p>
    </div>
  );
};

export default CheckBoxRef02;

 

 

<결과화면>

 

- 체크박스의 DOM에서 체크된 값을 읽어와서 value값만 골라 문자열로 합쳐 hobbies state에 넣는다

- 버튼 없이 체크박스를 선택하자마자 곧바로 결과 반영

 

 

CheckBoxRef3

 

 

hobbies를 문자열이 아닌 li태그(컴포넌트)로 분리하여 출력

 

 

<CheckBoxRef03>

import React, { useRef, useState } from "react";
import Hobby from "./Hobby";

const CheckBoxRef03 = () => {
  const [hobbies, setHobbies] = useState([]);
  const inputRef = useRef([]);

  const handleHobbiesOnChange = (e) => {
    if(e.target.checked){
      setHobbies([...hobbies, e.target.value])
    }else{
      setHobbies(hobbies.filter((hobby) => hobby !== e.target.value))
    }
    console.log(hobbies)
  } 

  const hobbyList = hobbies.map((hobby, i) => (
    <Hobby key={i} hobby={hobby} />
  ))
  
  return (
    <div>
      <div>
        <label>
          <span>Running</span>
          <input type="checkbox" value="Running" name="hobby"
          onChange={(e) => handleHobbiesOnChange(e)}  
          />
        </label>
        <label>
          <span>Reading Books</span>
          <input type="checkbox" value="Reading Books" name="hobby"
          onChange={(e) => handleHobbiesOnChange(e)}  
          />
        </label>
        <label>
          <span>Belly Dancing</span>
          <input type="checkbox" value="Belly Dancing" name="hobby"
          onChange={(e) => handleHobbiesOnChange(e)}  
          />
        </label>
      </div>

      <ul>
        {hobbyList}
      </ul>

    </div>
  );
};

export default CheckBoxRef03;

 

 

<Hobby 컴포넌트>

import React from 'react';

const Hobby = ({hobby}) => {
  return (
    <li>
      {hobby}
    </li>
  );
};

export default Hobby;

 

 

- 컴포넌트는 함수 단위로 분리하며, 확장성을 고려한 것

- 아이콘, 하이라이트, 상세정보 등 다양한 기능 및 스타일을 추가할 수 있다

 

 

<결과화면>

 

 

+

컴포넌트에 다양한 기능을 추가해 확장 가능

 

 

<수정된 Hobby 컴포넌트>

import React, { useState } from "react";

const iconMap = {
  "Running": "🏃‍♂️",
  "Reading Books": "📚",
  "Belly Dancing": "💃",
};

const Hobby = ({ hobby }) => {
  const [isHover, setIsHover] = useState(false);

  const style = {
    padding: "8px 12px",
    cursor: "pointer",
    listStyle: "none",
    display: "flex",
    alignItems: "center",
    gap: "8px",
    borderRadius: "6px",
    transition: "0.2s",
    backgroundColor: isHover ? "#f0f0f0" : "white",
    color: isHover ? "#0077ff" : "#333",
    fontSize: "15px"
  };

  return (
    <li
      style={style}
      onMouseEnter={() => setIsHover(true)}
      onMouseLeave={() => setIsHover(false)}
    >
      <span>{iconMap[hobby]}</span>
      <span>{hobby}</span>
    </li>
  );
};

export default Hobby;

 

 

<결과화면>

 

 

FoodContainer

 

 

사용자가 음식명을 국문/영문으로 입력하고 추가 버튼을 누르면 추가
각 메뉴는 체크박스 형태로 화면에 출력
사용자가 체크박스에 체크해 삭제버튼을 누르면 선택한 항목이 삭제된다

 

 

<FoodContainer>

import React from 'react';
import { useRef, useState } from "react";
import Food from "./Food";

const FoodContainer = () => {
  const inputRef = useRef([]);
  const [foods, setFood] = useState([]);
  const [checked, setChecked] = useState([]);

  const handleAddFoodOnClick = () => {
    const kor = inputRef.current[0].value;
    const eng = inputRef.current[1].value;
    setFood([...foods, { kor, eng }]);
    setChecked([...checked, false]);
  };

  const handleCheckedOnChange = (i) => {
    setChecked(checked.map((c, idx) => (idx === i ? !c : c)));
  };

  const handleDeleteFoodOnClick = () => {
    const newFood = foods.filter((_, i) => !checked[i]);
    setFood(newFood);
    setChecked(Array(newFood.length).fill(false));
  };

  const foodList = foods.map(({ kor, eng }, i) => (
    <Food 
      key={i}
      kor={kor}
      eng={eng}
      checked={checked[i]}
      onChange={() => handleCheckedOnChange(i)}
    />
  ));

  return (
    <div>
      <input type="text" placeholder="Add menu(Korean)" 
      	ref={(el) => inputRef.current[0] = el} />
      <input type="text" placeholder="English menu" 
      	ref={(el) => inputRef.current[1] = el} />
      <button onClick={handleAddFoodOnClick}>ADD</button>
      <button onClick={handleDeleteFoodOnClick}>DELETE</button>
      <ul>
        {foodList}
      </ul>
    </div>
  );
};

export default FoodContainer;

 

 

<Food 컴포넌트>

import React from 'react';

const Food = ({ kor, eng, checked, onChange }) => {
  return (
    <li>
      <input 
        type="checkbox" 
        checked={checked}
        onChange={onChange}
      />
      {`${kor} (${eng})`}
    </li>
  );
};

export default Food;

 

 

<결과화면>

 

 

- 체크박스를 클릭해 메뉴를 선택하고 DELETE버튼으로 메뉴 삭제 가능

 

 

 

https://developernew.tistory.com/431

 

리액트 React 설치방법 feat. VS Code

React란? React 리액트- 복잡한 사용자 인터페이스(UI)를 쉽게 구축하기 위해 페이스북에서 제작한 자바스크립트 기반의 라이브러리- 싱글 페이지 애플리케이션이나 모바일 애플리케이션 개발에 주

developernew.tistory.com

 

https://developernew.tistory.com/438

 

React 리액트 - 레퍼런스(Ref) useRef() vs useState()

useReference useRef란?: 저장공간 또는 DOM요소에 접근하기 위해 사용되는 React Hook- Ref는 reference, 즉 참조를 뜻한다- ref == DOM리액트는 돔을 지양하기 때문에 돔을 사용하는 것을 권장하지 않는다때문

developernew.tistory.com