
-상태관리를 하지 않으면 보일러 플레이트 및 프롭스 드릴링같은 구조적 문제가 생길 수 있습니다.
이러한 구조적 문제가 생기면 무거운 코드로 렌더링 시 시간이 오래 걸리고, 복잡한 구조로 인해 오류 파악 및 협업하는 사람들도 코드를 파악하기 어려우므로 상태관리가 필요합니다.
-전역 상태 관리를 할 수 있는 리덕스 툴킷을 이용하여 자주 사용하는 코드 및 변수를 관리합니다.
usecontext나 리덕스와 비교하면 사용이 더 쉽고 코드량이 가벼워 이용하고 있습니다.
또한 더 간편한 zustand를 공부하고 있습니다.
redux는 전역으로 상태관리가 가능한 라이브러리 입니다. redux는 크게 초기값, 리듀서, 저장소로 나뉘며 리듀서를 통해 상태 변화를 일으킵니다. 기존에 props로 데이터를 넘겨줄 때 부-자 관계로 단방향으로 전달 되었다면, 리덕스는 중앙에서 데이터를 관리하여 어떤 컴포넌트이든 전달이 가능하므로 사용합니다.
useContext 또한 전역 상태관리 라이브러리 입니다. redux처럼 중앙 데이터 관리를 할 수 있지만, 중앙 데이터 관리소에 데이터를 직접 담지 않고 상위페이지와 하위 페이지의 관계로 데이터를 전달합니다. 다만 props와 달리 데이터를 전달하지 않아도 되는 페이지를 생략하고 대신 중앙관리소가 상위 페이지와 하위 페이지를 연결합니다.
Q 상태관리를 왜 할까요? 그리고 평소 state 관리는 어떻게 하시나요?
A 상태관리는 반복되고 무거운 데이터를 전달하면서 생기는 구조적 문제들때문에 필요합니다.
만약 코드가 많으면 보일러 플레이트가 되고, 여러 컴포넌트에서 자주 사용하는 코드 및 변수를 관리하지 않으면 프롭스 드릴링이 됩니다.
이처럼 코드 구조가 문제가 생기면 렌더링 시 시간이 오래 걸리고 오류를 빨리 파악하기 어려우며, 협업하는 사람들도 코드를 파악하기 어렵습니다.
그렇기 때문에 클린코드, 즉 코드 구조 간편화를 위해 상황에 맞는 상태관리 라이브러리를 사용해야 합니다.
평소 리덕스 툴킷을 이용하여 자주 사용하는 코드 및 변수를 관리합니다.
usecontext나 리덕스와 비교하면 사용이 더 쉽고 코드가 가볍습니다.
usecontext는 전역으로 관리할 수 있으나 프롭스의 구조와 흡사하며 전달할 데이터가 많다면 구조가 복잡해집니다.
리덕스의 경우 리덕스 툴킷과 비슷한 구조를 가지지만 Action Value와 Action Creator를 이제 직접 생성해주지 않고, Action Value, Action Creator, Reducer가 하나로 합쳐졌다는 점에서 큰 차이점을 가집니다.
프로젝트에서 리덕스를 자주 사용해 익숙하지만 현재는 더 간편한 구조인 리덕스 툴킷을 사용합니다.
또한 현재 더 간편한 주스탄드 또한 학습중에 있습니다.
state를 다룰 수 있는 가장 기본적인 hook.
형태: const [state, setState] = useState(initialState);
일반 업데이트, 함수형 업데이트 방식.
단일 업데이트(batch update)로 리렌더링 방지.
props: 부모 컴포넌트가 자식 컴포넌트에게 물려준 데이터.
특징: 단방향성(부->자), 읽기 전용(변경x)
형태:
function Mother() {
const name = '홍부인';
return <Child motherName={name} />;
}
function Child(props){
console.log(props)
return <div>연결 성공</div>
}
children:자식 컴포넌트로 정보를 전달하는 또 다른 방법. props의 한 종류.
형태: layout 컴포넌트 예시
layout.tsx
//앞부분 생략
...
<div>
<Header/>
<main>
{ children }
</main>
</div>
App.tsx
//앞부분 생략
...
<Layout>
<Router/>
</Layout>
기존 props 구조 :할아버지=> 아버지 => 아들 => 손자
-할아버지에서 손자에게 값을 전달하기 위해 복잡한 과정: props drilling
props drilling: props가 깊어지면 오류 추척 어려움.
useContext: 전역 관리 라이브러리.
구조: 할아버지=> Context(중앙관리소) =>손자
형태:
grandfather.jsx
//생략
...
<FamilyContext.Provider value={{ houseName, pocketMoney }}>
<Father />
</FamilyContext.Provider>
);
child.jsx
//생략
...
const data = useContext(FamilyContext);
return(
//생략
...
<div>
{data.houseName}
</div>
)
단점: 전달할 값이 많아지면 복잡한 구조가 됨.
중앙 state 관리 라이브러리.
구조: initialState, reducer, configStore
예시:
//초기값
const initialState = {
number: 0,
};
//리듀서
const counter = (state = initialState, action) => {
switch (action.type) {
default:
return state;
}
};
//store 연결
// 원래 있던 코드
import { createStore } from "redux";
import { combineReducers } from "redux";
// 새롭게 추가한 부분
import counter from "../modules/counter";
const rootReducer = combineReducers({
counter: counter, // <-- 새롭게 추가한 부분
});
const store = createStore(rootReducer);
export default store;
redux를 발전시킨 상태관리 라이브러리
Action Value와 Action Creator를 이제 직접 생성해주지 않고, Action Value, Action Creator, Reducer가 하나로 합쳐졌다는 점이 큰 차이점.
형태:
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
number: 0,
};
const counterSlice = createSlice({
name: "counter",
initialState,
reducers: {
addNumber: (state, action) => {
state.number = state.number + action.payload;
}
},
});
// 액션크리에이터는 컴포넌트에서 사용하기 위해 export 하고
export const { addNumber, minusNumber } = counterSlice.actions;
// reducer 는 configStore에 등록하기 위해 export default 합니다.
export default counterSlice.reducer;
https://github.com/pmndrs/zustand
더 간편한 방식의 전역 상태 관리 라이브러리. usestate에 가까움.
import { create } from 'zustand'
const useBearStore = create((set) => ({
bears: 0,
increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
removeAllBears: () => set({ bears: 0 }),
}))
function BearCounter() {
const bears = useBearStore((state) => state.bears)
return <h1>{bears} around here ...</h1>
}
function Controls() {
const increasePopulation = useBearStore((state) => state.increasePopulation)
return <button onClick={increasePopulation}>one up</button>
}
리액트 전용 상태 관리 라이브러리.
atoms (공유 상태)에서 selectors (순수 함수)를 거쳐 React 컴포넌트로 내려가는 data-flow graph를 만들 수 있다.
형태:
const fontSizeState = atom({
key: 'fontSizeState',
default: 14,
});
function FontButton() {
const [fontSize, setFontSize] = useRecoilState(fontSizeState);
return (
<button onClick={() => setFontSize((size) => size + 1)} style={{fontSize}}>
Click to Enlarge
</button>
);
}
공식문서는 번역체여서 관련 블로그 글 참조하여 추후 다른 프로젝트 만들어볼 예정.