패스트캠퍼스 데브캠프 46~47일차 [Flux, Redux]

Su Min·2024년 7월 25일
0
post-thumbnail

민태강사님께서 리덕스를 공부하기에 가장 좋은 방법은 Flux아키텍처에 대한 공부를 우선적으로 한 이후 리덕스와 리덕스툴킷의 공식문서를 참고하여 공부하기를 권장하셨다.

🔗 Flux pattern

Action - > Dispatcher - > Model(store) - > View
사용자 입력 기반으로 Action을 만들고 Dispatcher에 전달하여 Store(Model)에서 데이터를 변경하고 View에 반영하는 단방향의 흐름인 아키텍처이다.

Action

Action은 간단한 javascript 객체이며 Dispatcher에게 전달되는 객체이다. 새로 발생되는 Action의 유형을 지정하는 type 속성이 있으며, 새로운 데이터를 보내는데 사용되는 payload 속성이 있다.

{ 
  type: "ADD_TODO", 
  payload: add
}

Dispatcher

Dispatcher는 store에 Action을 전달하는 역할이며 데이터의 흐름을 관리한다. store에는 Action의 type마다 콜백 함수가 있는데 Dispatcher가 전달하는 Action의 타입과 store에 등록된 type을 매칭하여 매칭된 store의 콜백 함수가 실행된다. store의 데이터를 조작하는 것은 Dispatcher만 가능하다.

Store

Store는 모든 상태를 가지고있는 저장소이며 상태를 변경할 로직을 가지고 있다. Action type에 따라 콜백함수를 Dispatcher에 등록하고, 콜백함수가 실행되고나서 상태가 변경되면 View에게 전달한다.

View

View는 리액트 컴포넌트라고 생각하면 된다. 최상위 View는 Store에서 변경된 데이터를 가져와 자식 View에게 내려보내고 데이터를 받은 View는 화면을 리렌더링한다. 사용자가 View에 어떠한 작업을 하면 그에 해당하는 Action을 생성한다.

🔗 Redux

자바스크립트 애플리케이션을 위한 상태 관리 라이브러리

Flux 아키텍처를 이용한 Redux의 데이터 흐름도 단방향이다. 리액트는 state를 관리하는 것이라면 리덕스는 이 state를 store에 보관하여 재사용하고 업데이트하는 등 리액트보다 상태 관리가 훨씬 용이하다.

Flux 와 Redux 차이

  • Flux와 달리 Redux에는 구조적으로 디스패처가 존재하지 않는다. 리덕스는 리듀서의 순수 함수들에 의존하고 있다.
  • Redux는 불변성(Immutable)특징을 가지기때문에 리덕스의 리듀서는 상태를 바꾸는 것이 아닌 항상 새로운 객체를 반환한다.
  • Flux는 다중 스토어를 사용하는 반면에 Redux는 단일 스토어이다.

Redux Toolkit

Redux 로직을 작성하기 위한 공식 권장 접근 방식으로 Redux코어를 둘러 싸고 있으며 Redux앱을 빌드하는데 필수적이라고 생각하는 패키지와 기능이 포함되어 있다. Redux Toolkit은 제안된 모범 사례를 기반으로하여 대부분의 Redux작업을 단순화하고 일반적인 실수를 방지하고 Redux 애플리케이션을 더 쉽게 작성할 수 있도록 한다.

공식 문서 "Redux가 Redux Toolkit을 사용하길 바라는 이유"

설치 npm install @reduxjs/toolkit

🔗 react-redux 시작하기

1. Store(Redux 저장소) 생성하기
2. Provider로 하위컴포넌트 감싸기
3. Reducer생성하고 store에 생성된 reducer추가
(해당 상태에 대한 모든 업데이트를 처리하도록 지시)
4. React컴포넌트에서 redux state 및 action사용
(useSelector저장소의 데이터 읽기, useDispatch을 사용하여 action전달)

🔗 Redux Store

Redux Store는 몇가지 methods가 있는 객체로 애플리게이션의 전체 상태 트리를 보유한다. 내부 상태를 변경하는 유일한 방법은 해당 상태에 대한 Action을 전달하는 것이다.

configureStore

앱의 전체 상태 트리를 보유하는 redux저장소(store)를 생성하는 리덕스툴킷 API로 앱 전체의 리듀서를 하나의 스토어로 모은다.

import { configureStore } from "@reduxjs/toolkit"
import counterSlice from "./reducer/counterSlice"
import todoReducer from "./reducer/todoSlice"

export default configureStore({
  reducer: {
    counter: counterSlice,
    todo: todoReducer,
  }
})

🔗 Redux Provider

Redux Provider는 Redux store를 모든 React 구성요소가 사용 할 수 있도록 한다.
구성요소 내부 트리에 최상위 수준에서 <Provider>를 렌더링하면 React의 Hooks 및 연결 API는 store 속성에 접근 할 수 있다.
Provider는 react-redux 라이브러리에서 제공된다.
설치 npm install react-redux --save

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import store from './store'
import { Provider } from 'react-redux'

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>,

🔗 Reducer

애플리케이션 상태의 변경사항을 결정하고 업데이트 된 상태를 반환하는 함수이며 store내부의 상태를 업데이트한다.

( previousState, action ) => nextState
이전 state와 action 객체를 받은 후에 next state을 return한다. 즉 reducer는 항상 현재 상태를 받고 필요한 것을 리턴하는데 그 리턴값이 state를 업데이트한다.

리덕스 툴킷을 사용하면 리듀서에서 mutating 로직을 작성할 수 있는데, immer 라이브러리를 사용하기때문에 실제로 상태를 변경하지 않는다. 초안 상태에 대한 변경사항을 감지하고 이러한 변경사항을 기반으로 완전히 새로운 불변(immutable) 상태를 생성한다. 이는 리듀서가 기존의 state를 변경하는 것이 아니라 하나 더 생성을 한 다음에 생성된 것으로 변환하여 불변성을 지켜준다는 뜻이다.

// Action 선언
const action = { 
	type: "INCREMENT"
}

function increment(amount){
	return {
		type: "INCREMENT",
		payload: amount
	}
}
// Reducer 선언
function reducer(state = {count: 0}, action){
  switch(action.type) {
    case "increment" :
      return {
        count: state.count + action.payload
      }
  }
}

createSlice( )

리덕스툴킷의 API인 createSlice는 리듀서 함수의 대상인 nameinitialState 을 받아 리듀서와 상태에 해당하는 액션 생성자와 액션 타입을 자동으로 생성하고 단일 구성 객체 매개변수를 가진 함수이다.
위의 Reducer 로직처럼 액션과 리듀서를 따로따로 정의하지 않아도 한번에 해결을 해주어 편리하다!!

export const counterSlice = createSlice({ 
  name: 'counter',
  
  initialState: {
    count: 0,
  },
  
  // reducer함수들의 객체
  reducers: { 
    increment: (state) => {
      state.value += 1;
    }, 
  
    decrement: (state) => { 
      state.value -= 1;
    }
  }
})
export const { increment, decrement } = counterSlice.actions;
export default counterSlice.reducer;

reducers 객체의 key이름은 action type을 생성하는데 사용된다. counter/increment 라는 action type상수가 생성되고 이에 상응하는 액션 타입을 가진 액션이 디스패치되면 리듀서가 실행된다.

🔗 Hooks를 사용하여 React에서 store에 접근하기

useSelector

provider로 둘러싸인 컴포넌트에서 store의 값을 가져 올 수 있다.
const result = useSelector((state)=> state.result)

import { useSelector } from 'react-redux'
.
.
    const count = useSelector((state) => state.counter.count)
.
.
  return (
    <p}>{ count }</p>
  )
.
.

useDispatch

store에 있는 dispatch 함수에 접근하는 hooks

import { useDispatch } from 'react-redux'
.
.
  const dispatch = useDispatch()
.
.
  return (
    <button onClick={()=>dispatch(increment())}>증가</button>
  )
.
.
profile
성장하는 과정에서 성취감을 통해 희열을 느낍니다⚡️

0개의 댓글

관련 채용 정보