[React] Redux

Haeseo Lee·2023년 4월 7일
0

React

목록 보기
10/16
post-thumbnail
post-custom-banner

Redux

상태관리 라이브러리
예측 가능한 상태 컨테이너 제공

store에 상태를 넣어두고 필요한 컴포넌트에서 가져다 사용

설치

npm i redux --save

사용이유

- props로 다 내려줄 수 없을 만큼 여러 위치에 많은 양의 상태 값이 존재할 때
- 업데이트 로직이 복잡할 때
- 시간이 지남에 따른 상태 값의 변화에 대한 추적 용이
- 사이드이펙트나 리렌더링을 줄이기 좋음

store에서 모든 state를 관리하고 있고, action을 dispatch해야 reducer가 state를 업데이트
-> 그 후 해당 state를 구독하는 컴포넌트들이 선택적으로 리렌더링

Action

  • 상태값에 대해 수행할 작업
    • type: 수행할 작업의 유형 (ex: 리스트에 값 추가, 서버에서 값을 받아오기, 수 증가 등등)
  • dispatch()를 통해 연결
{ type: 'LIKE_ARTICLE', articleId: 42 }
{ type: 'FETCH_USER_SUCCESS', response: { id: 3, name: 'Mary' } }
{ type: 'ADD_TODO', text: 'Read the Redux docs.' }

Reducer

  • 특정 상태에 대해 Action을 토대로 Store 내부를 업데이트하고 변경된 상태 값을 반환하는 함수
  • 쉽게 말해 데이터를 수정하는 방법을 정의해놓은 것
const counter = (state = 0, action: { type: string }) => {
  switch (action.type) {
    case "INCREMENT":
        return state + 1;
    case "DECREMENT":
        return state - 1;
    default:
        return state;
  }
}
  • Reducer는 순수 함수이기 때문에 내부에서
    • state 자체에 대해 변경 X
    • side effect(e.g. API 호출, 라우팅) 수행 X
    • 비순수 함수(e.g. Date.now(), Math.random()) 호출 X

  • 여러 Reducer를 쓰고 싶다면 combineReducers()로 묶어서 사용
    • store에 Reducer는 하나만 존재해야 하기 때문
    • 아래 예시에서 store가 사용할 Reducer는 rootReducer인 셈
import React from 'react'
import { combineReducers } from 'redux';
import counter from './counter';
import todos from './todos';
import posts from './posts';

const rootReducer = combineReducers({
    counter,
    todos,
    posts
});

export default rootReducer;

export type RootState = ReturnType<typeof rootReducer>;

Store

  • 애플리케이션의 전체 상태 저장소 (상태 트리 보유)
  • 다른 곳에서 내부 상태를 변경하려면 해당 상태에 대해 Action을 전달해야 함
  • 클래스가 아니고 객체임
import { createStore, } from 'redux';
import counter from './reducers/counter';

const store = createStore(counter);

Redux로 상태관리

getState()

  • 애플리케이션의 현재 상태 값 반환 (store의 Reducer가 반환한 마지막 값)

dispatch()

  • 특정 Reducer를 동작시킬 수 있음
const render = () => root.render(
  <React.StrictMode>
	  <App 
	    value={store.getState()}
      onIncrement={() => store.dispatch({ type: 'INCREMENT' })}
      onDecrement={() => store.dispatch({ type: 'DECREMENT' })}
    />
  </React.StrictMode>
);

subscribe()

  • state가 변경된 값을 렌더링하기 위해 필요.
  • Reducer가 호출될 때마다 subscribe되어 있는 함수나 객체를 호출
store.subscribe(render);

React-Redux

npm i react-redux --save

Provider

  • Redux store에 액세스해야 하는 모든 컴포넌트에서 store를 사용할 수 있게끔 함
  • 보통 최상위 수준에서 렌더링
  • 예시
import { Provider } from 'react-redux';

const render = () => root.render(
  <React.StrictMode>
    <Provider store={store}>
      <App 
        value={store.getState()}
        onIncrement={() => store.dispatch({ type: 'INCREMENT' })}
        onDecrement={() => store.dispatch({ type: 'DECREMENT' })}
      />
    </Provider>
  </React.StrictMode>
);

useSelector()

  • store에서 가져올 state 선택
import { useSelector } from 'react-redux';

const todos: string[] = useSelector((state: RootState) => state.todos);
const counter = useSelector((state: RootState) => state.counter);
const posts: Post[] = useSelector((state: RootState) => state.posts);

useDispatch()

  • store의 dispatch() 함수를 가져와서 사용
import { useDispatch } from 'react-reduxs';

const dispatch = useDispatch();

dispatch(...수행할 action...);
profile
잡생각 많은 인간
post-custom-banner

0개의 댓글