logo

Post

Redux에 대한 주관적인 정리

게시글 대표 이미지

들어가며

Redux는 무엇이고 왜 쓰는 걸까?

React도 어려운데 React를 배우다보면 거기서 파생된 것으로 보이는 여러가지 것들을 또 만나게 된다. 일단 무릇 기술의 존재 이유가 그렇듯 쓰면 좋으니까 사용하는 걸텐데 초보자 입장에선 오히려 부담으로 먼저 다가온다. 그렇다고 안 배울 수도 없고, 하다 못해 내가 쓰지 않더라도 남이 쓴 코드를 알아보려면 기본은 알아야 하지 않겠나. 그래서 최대한 쉽고 간단하게, 주관적이고 얕은 레벨에서 Redux에 대해 정리하고자 한다.

Redux는 왜 쓸까?

한 마디로 요약하자면 상태 관리에 용이하기 때문에 쓴다. 조금 더 나누자면,

  • 깊숙한 컴포넌트까지 props를 전달해주는 게 너무 번거로울 때
  • state를 잘 관리하고 싶을 때 쓴다.

번거로운 props 전달

기본적으로 React는 UI 요소를 컴포넌트로 만들어 재사용하기 위해 존재한다. 당연히 컴포넌트 안에서 다른 컴포넌트를 자식 컴포넌트로 사용하는 것도 가능하다.

각 컴포넌트에 필요한 상태는 state라는 특수한 변수에 담아 관리한다. 말그대로 어떤 상태를 나타내는 변수다. state를 선언한 컴포넌트 안에서 사용할 거라면 상관 없겠지만 개발을 하다 보면 이 state를 자식 컴포넌트 안에서도 사용해야 하는 상황이 나오기 마련이다. 그때 이용되는 것이 props 문법이다. 일종의 전송 수단이라고 볼 수 있다.

그런데 컴포넌트 안에 컴포넌트 안에 컴포넌트... 이런 식으로 계속해서 컴포넌트가 중첩된 상태라고 해보자. 그렇다면 가장 상위 컴포넌트에서 선언한 state를 가장 내부에 있는 컴포넌트에 전달해주기 위해 그 중첩횟수만큼이나 props를 통해 전달해주어야 한다. 우리 개발자는 이런 중복을 피하고 싶다. 귀찮기도 하고. 지금이 바로 Redux가 멋지게 등장하는 지점이다.

Redux를 사용하면 state를 보관하는 저장소(store.js)를 만들 수 있다. 그리고 여기에 관리하고 싶은 state를 보관하면 된다. 이렇게 해놓으면 모든 컴포넌트는 이 저장소로부터 state를 꺼내 쓸 수 있게 된다. (낙수효과를 기대하는 것보다 수혜 타겟한테 직접 돈을 주는 게 더 직관적이라는 비유가 떠오르는 건 주제를 너무 벗어났으려나) 이것으로 코드가 한결 간결해질 수 있다.

사용 예시

// index.jsx
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux'
import { createStore, applyMiddleware } from 'redux';

import App from './App';

const state = {
	// ...
}

function reducer(state, action) {
	return {
	...state,
	// ...
	}
}

const store = createStore(reducer);

ReactDOM.render(
  (
    <Provider store={store}>
      <App />
    </Provider>
  ),
  document.getElementById('app'),
);

// MyComponent.jsx
import { useSelector } from 'react-redux';

export default function MyComponent() {
	const dataFromStore = useSelector( (state) => state );

	return (
		// ...
	);
}

보다시피 모든 컴포넌트가 props없이 state를 직접 꺼내어 쓸 수 있다.

상태 관리의 편리함

상태 관리, 즉 state를 보다 편리하게 관리할 수 있게 해준다.

state를 꺼내어 쓴 컴포넌트 안에서 state의 값을 변경하고 싶을 때가 있다. 물론 그 컴포넌트 안에서 값을 직접 변경하는 것도 가능하다. 다만 이렇게 했을 경우 문제가 생겼을 때 원인을 찾아 바로잡는 것이 매우 힘들어진다. 어떤 컴포넌트에서 잘못된 방식으로 state를 다루었는지 알 수가 없기 때문에 의심가는 순서대로 일일이 확인하는 수밖에 없다. 또 다시 Redux가 멋지게 등장할 타이밍이다.

Redux를 사용하면 state를 다루는 방법에 대해 미리 정해놓을 수 있다. 이렇게 함으로써 각 컴포넌트는 state를 직접 변경하지 않고 그렇게 해달라고 요청만 하게 된다. 마치 API를 만들어 놓고, 만들어진 API를 가져다 쓰는 것과 비슷하다. 이는 컴포넌트가 그 본연의 기능인 UI 요소 렌더링에 더욱 집중하게 해준다. 이제 아까와 같은 문제는 사라졌다. 뭔가 잘못된 방식으로 state가 변경되고 있다고 해서 모든 컴포넌트를 전수조사할 필요가 없다. 컴포넌트는 변경을 요청했을 뿐이니까. 이것으로 우리는 문제를 보다 간편하게 추적하고 디버깅할 수 있게 되었다.

사용 예시

// state가 저장된 곳은 store, 변경 방법은 action, 그걸 전달하는 걸 reducer라 부른다.
 
// reducer.js
// ...
export function reducer(state = initialState, action) {
	if (action.type === 'someAction') {
		// state를 다루는 방법 내용
	}
	// ...
}

// MyComponent.jsx
import { useDispatch, useSelector } from 'react-redux';

export default function MyComponent() {
	const dataFromStore = useSelector( (state) => state );
	const dispatch = useDispatch();

	return (
		<div>
			// ...
			<button
        type="button"
        onClick={() => {
          dispatch({ type: 'someAction' });
        }}
      >
        상태 변경
      </button>
		</div>
	);
다른 글 읽기
이전 글
  • Cover Image for 좋은 리액트 상태 관리에 대해 고민해보자!
      좋은 리액트 상태 관리에 대해 고민해보자!

      좋은 라이브러리가 많아서 오히려 더 고민이 많아지는 아이러니...

    • 다음 글
    • Cover Image for null 병합 연산자 (??)
        null 병합 연산자 (??)

        "||" 이면 충분한 거 아니야?!