-
[React] StateStudy/React 2025. 12. 26. 20:20
Props 의 한계
기존의 Props 를 사용하면, 하나의 컴포넌트 파일을 사용하여 내용만 다른 여러 개의 컴포넌트를 만들 수 있다.
하지만 props 자체로는 몇 가지 한계가 존재한다.
- 내용을 설정하기 위해서는 반드시 상위 컴포넌트에서 값을 내려받아야 한다.
- 상위 컴포넌트로부터 받은 값은 수정할 수 없다.
이를 보완하기 위한 방식이 바로 State 다.
State
React 컴포넌트 내부에서 동적으로 사용 및 관리되는 데이터(값)
특징
- 관리하고자 하는 컴포넌트의 내부에서 선언된다.
- 값은 얼마든지 수정 가능하며, 초기값 설정이 가능하다.
- 값이 변경되면, 화면이 새로 렌더링(Rendering) 된다.
State 의 선언 및 관리 방식
대표적인 방식으로 useState 와 useReducer 가 있다.
useState
: 일반적으로 사용되는 방식
import { useState } from "react"; const [state, setState] = useState(initialState);setState
: state의 값을 변경하는 함수
: 일반적으로 state 앞에 set 이 붙은 형태의 이름을 가짐 (ex. [count, setCount])
initialState
: state의 초기값
: 생략 가능 (생략하는 경우, state의 타입에 따라 자동으로 추론됨)
: 함수의 반환값으로 설정 가능
const [value, setValue] = useState(() => getValue());useReducer
: useState 에서 심화된 방식
import { useReducer } from "react"; const [state, dispatch] = useReducer(reducer, initialState, initFunc);dispatch
: reducer 를 실행하는 함수
reducer
: state의 값을 변경하는 함수
initialState
: state의 초기값
: 생략 불가
initFunc
: state 를 초기화하는 함수
: 생략 가능
const createInitialState = (value) => { return value === 0 ? 100 : value } // state 의 초기값 = 100 const [state, dispatch] = useReducer(reducer, 0, createInitialState);
useState vs useReducer
공통점
- 원시형 데이터 (Number, String, Boolean) 와 참조형 데이터 (Array, Object) 모두 State 로 사용이 가능하다.
import { useReducer, useState } from 'react' // 원시형 (Number) // useState const [sState, setState] = useState(1); // useReducer const [rState, dispatch] = useReducer(reducer, 1); // 참조형 (Object) // useState const [sState, setState] = useState({count: 1}); // useReducer const [rState, dispatch] = useReducer(reducer, {count: 1});- React Hook 에 해당하여 반드시 컴포넌트의 최상위에 선언되어야 한다.
import { useReducer, useState } from 'react'; function Component() { const [sState, setState] = useState(1); const [rState, dispatch] = useReducer(reducer, 1); // ... return <div></div> }- state 를 하위 컴포넌트에 props 로 전달할 수 있다.
import { useReducer, useState } from 'react'; function Component() { const [sState, setState] = useState(1); const [rState, dispatch] = useReducer(reducer, 1); // ... return ( <div> <Child value={sState} /> <Child value={rState} /> </div> ) }- state 를 Batch (일괄 처리) 방식으로 Update 한다.
Batch Update
: 하나의 변경 함수에서 state 를 여러 번 변경하는 경우, 너무 많은 리렌더링(Re-Rendering) 을 방지하기 위해, 하나의 변경 함수가 끝날 때까지 기다렸다가 일괄적으로 state 를 변경하는 방식
: 변경된 중간값을 사용하고자 하는 경우, 이전 값을 사용하는 함수 형태로 setState 를 작성해야 한다.
import { useState } from 'react'; function Test() { const [count, setCount] = useState(0); // count 는 handleClick1 이 끝날 때까지 계속해서 0 (0 -> 1) const handleClick1 = () => { setCount(count + 1); setCount(count + 1); }; // 함수를 넣어 이전 값을 사용 (0 -> 1 -> 2) const handleClick2 = () => { setCount(n => n + 1); setCount(n => n + 1); }; return ( <div> <button onClick={handleClick1}>버튼1</button> <button onClick={handleClick2}>버튼2</button> </div> ) };차이점 (= useReducer 의 사용법)
만일 하나의 컴포넌트 안에서 여러 개의 state 를 useState 로 관리하게 된다면, 다음과 같은 코드가 나올 것이다.
import { useState } from 'react'; const [num, setNum] = useState(0); const [text, setText] = useState(""); const [bool, setBool] = useState(false); const handleNumChange = (value: number) => { setNum(value); }; const handleTextChange = (value: string) => { setText(value); } const handleBoolChange = (value: boolean) => { setBool(value); }각 state 와 변경 함수를 직접적으로 보고 관리할 수 있어 가독성은 좋지만, 개수가 계속해서 늘어난다면 오히려 관리하기가 힘들어진다.
그런 경우에 useReducer 를 사용하면 reducer 로 각각을 정의하여 깔끔하게 설정할 수 있다.
import { useReducer } from 'react'; // 초기값 const initialState = {num: 0, text: '', bool: false} const [state, dispatch] = useReducer(reducer, initialState) // reducer const reducer = (state, action) => { switch(action.type) { case "setAge": return {...state, num: action.payload }; case "setText": return {...state, text: action.payload }; case "setBool": return {...state, bool: action.payload }; default: return state } };Reducer
: action 을 입력 받아, action 에 따라 state 변경 함수를 수행한다.
: 일반적으로 action 내부에 type과 payload 를 작성한다.
: payload 는 선택사항이다.
const reducer = (state, action) => { switch (action.type) { case 'plusNum': return {...state, num: num + 1}; } }; /** ...state * - 참조형 state 의 경우, 특정 값만 변경시키기 위해, 나머지 값들은 그대로 전개한다. */
: 참조형 데이터가 아니더라도 reducer 생성이 가능하다.
import { useReducer } from 'react'; const [state, dispatch] = useReducer(reducer, 0); const reducer = (value, action) => { switch(action.type) { case 'plus': return value + 1; case 'minus': return value - 1; } };reducer 실행 방법
: dispatch 에 action 정보를 같이 전달한다.
import { useReducer } from 'react'; function Component() { const [state, dispatch] = useReducer(reducer, 0) const reducer = (state, action) => { switch(action.type) { case 'plus': return state + action.payload; case 'minus': return state - action.payload; default: return state; } }; const handleClick = () => { dispatch({type: 'plus', payload: 5}); }; return ( <button onClick={handleClick}>+5</button> ) }'Study > React' 카테고리의 다른 글
[React] DOM & 렌더링 (Rendering) (0) 2025.12.29 [React] 컴포넌트 (Component) (0) 2025.12.19