처음 만난 Redux

김민석·2021년 4월 6일
0

Redux

목록 보기
1/5

Redux를 처음 만났다.

그댈 처음 만난 순간🤬

정신 사나운 Redux...
헷갈리는 Redux...
🤯🤯🤯🤯🤯🤯🤯🤯

처음 봤을 때는 굳이 이걸 사용해야하나? 라는 생각이 들었다.

정돈되어 있다는 느낌이 들지않고 주먹구구 식으로 막 가져다 붙인 것 같은 느낌이 들었다.

그런데 보다보니 정돈되어 있지 않은 것은 내 머릿속🤯🤯이었다.. ㅎ


(갓 생활코딩)

그래도 조금은 익듁해졌다.

얼마나 익듁 해졌는지 정리해보자.

순서

처음 redux를 만났을 때의 가장 큰 문제점은 인터넷에서 찾아볼 수 있는 대부분의 예시들이 각 부분을 모듈화했기 때문에 일어났다.

무엇이 어디 사용되고, 무엇과 무엇이 연결되어 있는지 도통 알 수가 없었다.

그럴 땐 👇 이 아이를 보자.

1) 초기 state를 정의

2) action
   객체를 리턴하는 action creator 함수를 작성

3) reducer
   action 의 타입에 따라서 새로운 state를 생성해내는 순수 함수


4) reducer를 이용한 store 생성

이 순서를 따라가면 된다. (모듈화는 이것들을 따로 떼어놓은 것 뿐이다.)

action creator

action Creator는 action 객체를 만들어주는 함수다.
이것의 형태는 따로 정해져 있는 것이 아니라,
내가 마음대로 함수를 짜되, action 객체의 형식에 맞춰서 어떠한 객체를 리턴하게 만들어 주면 된다.

이 객체는 이런 식으로 생겼다.

{type : 'ACTION'
 payload: {...}
}

이렇게 만들어진 객체는 reducer 함수로 들어가는데,
이때 action 객체의 type에 할당된 값에 따라 reducer 함수가 분기를 나눈다.


reducer

action 객체와 현재의 state를 인자로 받아서 새로운 state를 생성해준다.

export const postsReducer = (prevState = initPosts, action) => {
    switch(action.type){
        case ADD_POST :
            return Object.assign({}, prevState, {
                ...prevState,
                posts : [...prevState.posts, action.post]
            })

        default:
            return prevState
    }
}

이런 식으로 분기를 만들어 action으로 들어오는 객체들의 type에 따라 그에 맞는 State를 리턴한다.

combineReducer

프로젝트가 복잡해지면 reducer 함수가 대응해야하는 조건이 비대해져서 힘들어질 것이다.
이때, 각 reducer를 분리하여 합치는 API가 combineReducer다.

const rootReducer = combineReducers({
    name : nameReducer,
    posts : postsReducer
}) 
export default rootReducer
const rootReducer = combineReducers({
    nameReducer,
    postsReducer
}) 
export default rootReducer

두 코드 모두 '거의' 같은 결과를 보여준다.

state 를 살펴보면

전자는

{name : {...},
  posts : {...}
}

후자는

{nameReducer : {...},
  postsReducer : {...}
}

차이는 별것이 아니지만 이를 보고 redux가 어떻게 작동하는지 전체적인 흐름을 볼 수 있었다.

store가 생성될 때 전달된 reducer는 dispatch를 통해 reducer가 특정한 객체를 리턴할 때마다, 그 결과값을 토대로 새로운 state를 만드는 것으로 보인다.

따라서, 위의 예시에서 보여지는 차이는, 아래에서 볼 createStore가 각 reducer의 initialstate를 토대로,
state에 key:value를 생성하기 때문에 저런 차이가 보여지는 것이다.
combineReducer는 각 Reducer가 리턴하는 값을 store에게 전달하기 이전에 다시 하나로 묶어주고 있는 것 같다.


Store

createStore
Store는 Reducer를 인자로 전달하여 사용한다.

reducer는 나중에 dispath를 통해 reducer 안으로 정보를 넣어 가공하는 역할을 한다.

이때, 각 reducer 들에 initial state를 지정해도 되지만, createStore 시에 initalstate를 두 번째 인자로 전달해 줄 수 있다.




With React Hooks

위의 내용에서 달라지는 것은 없다.

다만 store에서 state를 불러오거나, dispatch를 할 때 방식이 바뀌는 것, 또한 React에서 다른 Component들이 State를 사용할 수 있게 만들어주는 것들이 다르다. (현재 내가 알기까지는...)

위 3가지는 아래의 예시를 보면 된다.

import { useSelector, useDispatch } from 'react-redux'
import { addPost, changeName  } from '../actions/actions'
import { useState, useRef } from 'react'

const Display = (props) => {

    const { name, posts } = useSelector(state=>state)
    const [ value, setValue ] = useState('')
    const dispatch = useDispatch()

    
    {... 중략}

    const handleClick = (e) => {
        dispatch(changeName(value))
        setValue('')
    }

    {... 후략}
}

const store = createStore(rootReducer)

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

* useSelector

useSelector는 store에서 data를 가져오는 것이다. 이때 useSelector는 자동으로 subscribe한다.
따라서 state가 바뀌면 자동으로 컴포넌트가 rerendering 될 것이다.

useSelector(state=>state.value)

store.getState().value 

이 두 가지가 같은 결과를 내보인다고 생각하면 된다.

!!! 성능을 위해 개선할 수 있는 방법이 있는 것으로 보인다. 추후 필요할 시 공부할 것!


* useDispatch

이 부분은 순수 Redux와 완전 같다!

감싸주기!

const store = createStore(rootReducer)

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

Provider는 APP 안에 있는 모든 컴포넌트가 store에 접근 할 수 있게 만든다.

0개의 댓글