+ Redux에 대해 공부한 것을 정리한 것입니다. 배우는 중이라 잘못된 내용이 있을 수 있으며 계속해서 보완해 나갈 것입니다. :))
앞서서 Redux에서 사용하는 Action, Store 그리고 Reducer의 의미와 특징을 살펴보았다.
여기서는 Redux을 배우고, 활용할 때 등장하는 State, Store, reducer,action등의 역할과 서로 어떻게 연관되어 작동하게 되는지를 정리해보고자 한다.
1. State(상태)
React를 배울 때 처음 접한 State는 컴포넌트 내부적을 사용하는 데이터의 집합이다. 유튜브라면, 상태는 재생되고 있는 비디오 정보, 화면 비디오 리스트에 출력되는 비디오들의 정보, 다크모드 여부, 등이 될 수 있다.
앞선 유튜브 클론 코딩을 통해 state는 어떤 event나 API등을 통해 setState 메서드를 사용하여 바뀔 수 있는 것을 배웠다. 그리고 앱은 state를 읽어와서 화면에 그에 맞는 UI를 출력하게 된다.
그런데 앞에서도 살펴보았듯이 React와 React에서의 state사용방식 만으로는 '너무 많은 props를 내려야 하는 경우'와 '너무 깊은 곳에 props를 전달해야 하는 경우' 가 생길테고,
그러면
" 어떻게 이 문제를 해결할 수 있을까? 컴포넌트가 접근 할 수 있는 공용스토어(Store)가 있다면? 그럼 하위 컴포넌트든 상위 컴포넌트든 상관없이 각 컴포넌트가 자신이 필요할 때 스토어에 접근해서 가져오면 되지 않을까?
그리고 state 변경이 이루어질 수 있게 하는 것(Action) 과 state 변경을 해주는 Action을 스토어까지 가져와주는 스토어 관리자(Dispatcher)가 스토어의 상태 변경을 관리하면 불필요한 혼란이 줄지 않을까? "
이러한 역할을 해주는 것이 Redux이고, store, reducer, dispatch, subscribe, getState, action등의 개념이 등장한다.
2. Store
Store는 state의 관리를 하는 전용 장소로,
아래처럼 state들이 store에 객체형식으로 저장된다.
{
type: "ORDER",
drink: {
menu: "Americano",
size: "Grande",
iced: false
}
}
또한 규모가 클 경우에는 아래처럼 state를 카테고리별로 분류하는 경우가 일반적이라고 한다. (reference)
{
// 세션과 관련된 것
session: {
loggedIn: true,
user: {
id: "114514",
screenName: "@mpyw",
},
},
// 표시중인 타임라인에 관련된 것
timeline: {
type: "home",
statuses: [
{id: 1, screenName: "@mpyw", text: "hello"},
{id: 2, screenName: "@mpyw", text: "bye"},
],
},
// 알림과 관련된 것
notification: [],
}
출처: 아마 이게 제일 이해하기 쉬울걸요? React+Redux 플로우의 이해 by carrot useless
2-1. Store의 생성
//1. store을 만든다. - Redux의 createStore API를 사용하고, createStore의 입력값은 Reducer함수이다.
// import { createStore } from 'redux'
let store = Redux.createStore(reducer);
2-2. Store의 예
import React from 'react'
import ReactDOM from 'react-dom'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import App from './containers/App'
import reducers from './reducers'
const store = createStore(
reducers,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(),
)
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('app'),
)
2-3. Store의 주요 메서드
- createStore(reducer)로 Redux store를 생성할 수 있다.
- getState()를 통해 현재 state를 가져올 수 있다.
- dispatch(action)을 사용하여, store의 reducer에 action을 전달한다. redux에서 상태 변경을 일으킬 수 있는 유일한 방법이다.
3. Reducer
Action은 뒤에서 다루겠지만 간단히만 말하자면 Store에 대해 뭔가를 하고싶거나 store의 state를 업데이트하고 싶을 때 발생하는 이벤트 드리븐같은 것이다. 이 Action은 Reducer로 전달된다.
Action을 전달받는 Reducer는 각 Action이 Store를 어떻게 업데이트할지를 기술하는 순수 함수이다. tore와 정보를 주고받는 역할을 한다. 업데이트 방식은 store의 state를 변형(muatate)하는 것이 아닌 '이전 state와 Action을 참고하여 새로운 state를 만들어서 반환하는 방식이다 .
3-1. Reducer의 정의
항상 state와 action을 받아서 state를 return 해주어야한다.
//createStore의 입력값으로 넣어주는 reducer는 action값과 기존의 state값을 참조해서 새로운 state를 만든다.
function reducer([기존의 state], [action]){
if([기존의 state]값 === undefined){ //아직 해당 state가 정의되지 않았으면
return({[초기 state값 key]: [value]}//초기값으로 초기화를 해줘야함
}
}
3-2. Reducer의 예
import { SET_USERNAME, SET_DARK_MODE } from '../actions/index'
const initialState = {
currentUser: { name: 'Hyeonjeong' },
darkMode: false,
}
const settingReducer = (state = initialState, action) => {
let newState
switch (action.type) {
case SET_USERNAME:
newState = Object.assign({}, state, { currentUser: { name: action.name } })
break
case SET_DARK_MODE:
newState = Object.assign({}, state, { darkMode: action.value })
break
default:
return state
}
return newState
}
export default settingReducer
3-3. Reducer의 예에서 보이는 'Object.assign'은 왜 쓰고, 어떻게 작동하는가
Reducer는 이전 state와 Action을 참고하여 새로운 state를 만들어서 반환하는 방식이다. 그래서 원본 state 객체를 직접 변경하지 않고, 객체에 새 값을 적용하기 위해 Object.asssign을 사용한다.
Object.assign(대상 객체(target), 하나 이상의 출처 객체(sources))
Object.assign() 메소드는 열거할 수 있는 하나 이상의 출처 객체로부터 대상 객체로 속성을 복사할 때 사용한다. 대상 객체를 반환합니다.
이때 주목할 특징은 '동일한 키가 존재할 경우 대상 객체의 속성은 출처 객체의 속성으로 덮어쓰여진다'는 것이다.
그래서
Object.assign({}, {currentUser:{name: 'Hyeonjeong'}}, {currentUser: {name: action.name}}) 이면 currentUser가 동일한 키이기 때문에 {name: 'Hyeonjeong'}자리에 {name: action.name}이 새로 덮어 씌워진 'currentUser: {name: action.name}'인 새state가 생성되는 것이다.
3-4. state객체가 복잡하게 짜여진 경우(수정하고 싶은 state가 아주 깊은 구조로 되어 있는 경우) 그 안의 내용이 바뀐 새로운 state를 어떻게 만들 수 있을까
currentUser: {
name: "김코딩",
company: {
name: "Coggle",
department: "Development",
role: {
name: "Software Engineer",
}
}
}
//에서 "Software Engineer"라는 값을 바꾸는 좋은 방법?
이런 상황을 위해 좀더 쉽게 해줄수 있는 Library 가 많이 들어봤을 Immutable.js 이다.([출처] 13. react-tutorial 고급 (불변성 - Immutability 개념)|작성자 JeromeBaek)
이와 관련된 내용은
https://ko.redux.js.org/recipes/structuring-reducers/immutable-update-patterns/
https://blog.naver.com/backsajang420/221358585344
을 참고하여서 더 공부가 필요하다.
3-5. Reducer 주요 메서드
combineReducers(reducer1, reducer2, ...): 여러 개의 reducer들을 하나로 합칠 수 있다.
4. Action
Action은 상태 변경을 일으키는 이벤트에 대한 정적인 정보이다. Reducer가 Action과 이전 state을 참고해서 새로운 state를 만들기 때문에 Action은 reducer가 구분 할 수 있도록 액션의 이름(타입) 과 데이터를 가진 객체형식이다.
3-1. Action의 정의
{
type: [액션의 종류를 식별할 수 있는 문자열 혹은 심볼],
[액션의 실행에 필요한 임의의 데이터],
}
3-2. Action의 예(Reducer와 action을 이용해서 새로운 state값 만들기)
export const SET_USERNAME = 'SET_USERNAME'
export const SET_DARK_MODE = 'SET_DARK_MODE'
export const SET_CURRENT_VIDEO = 'SET_CURRENT_VIDEO'
export const setUsername = (name) => ({
type: SET_USERNAME,
name,
})
export const setDarkMode = (value) => ({
type: SET_DARK_MODE,
value,
})
export const setCurrentVideo = (video) => ({
type: SET_CURRENT_VIDEO,
video,
})
'Dev > SW Engineering' 카테고리의 다른 글
28. Redux - Redux의 작동방식3. React-Redux를 통해 상태 수정하기 (0) | 2020.07.28 |
---|---|
27. Redux - Redux의 작동방식2. React-Redux를 통해 상태 사용하기 (0) | 2020.07.28 |
25. Redux - Redux의 필요성과 써야 할 때를 구분할 줄 알기 (0) | 2020.07.25 |
[CSS] CSS 개념 복습 (0) | 2020.07.21 |
[HTML] HTML 태그 복습 (0) | 2020.07.21 |