#2858 ๋ฐ ์ด์ #2295์ ์ฃผ์์ ๋ฐ๋ฅด๋ฉด Redux ์ฝ์ด + ๋ช ๊ฐ์ง ์ผ๋ฐ์ ์ธ ๋ฏธ๋ค์จ์ด + ์คํ ์ด ์ธํธ์ + ๊ธฐํ ๋๊ตฌ๋ก ๊ตฌ์ฑ๋ ์ฌ์ ๊ตฌ์ฑ๋ ์คํํฐ ํคํธ๊ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์์ํ๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค.
๋๋ ํจํค์ง ์ด๋ฆ์ ์์ฝํ๋ ๊ฒ์ผ๋ก ์์ํ๊ณ (๊ทธ๋ ์ง๋ง ์์ง ๊ฒฐ์ ํ์ง ์์์ต๋๋ค) ๊ฑฐ๊ธฐ์์ ๊ณต๋ฐฑ์ ์ฑ์ฐ๊ธฐ ์์ํ ์ ์์ต๋๋ค. ๋๋ ๊ทธ ํจํค์ง์ ๋ด์ฉ์ ์ฌ๊ธฐ์ ์ ์งํ๊ณ ์ถ์ต๋๋ค. ๊ทธ๋์ ์ฐ๋ฆฌ๋ ๋ค๋ฅธ repo๋ ๋ค๋ฅธ ๊ฒ์ ์ค์ ํ ํ์๊ฐ ์์ต๋๋ค. ์ฐ๋ฆฌ๋ ๋ชจ๋ ธ๋ ํฌ๋ฅผ ์กฐ์ฌํ๊ณ ์ถ์ ์๋ ์์ง๋ง ํ์ฌ ๊ธด๊ธํ ํ์์ฑ์ด ์๋ค๊ณ ์๊ฐํ์ง ์์ต๋๋ค.
๋์์ ์กฐ์ฌํ๊ณ ์ถ์ ํ ๊ฐ์ง๋ combineReducers
๋ฅผ ์์ฒด ํจํค์ง๋ก ๋ถํ ํ๋ ๊ฒ์
๋๋ค. ์์ ์ ๊ตฌ์ฑํ๊ณ ์ด์ํ๋ ๋ฐฉ๋ฒ์ ๋ํด ๊ท์ ํ๋ ์ ์ผํ ๊ฒ์
๋๋ค. ๋ถ๋ช
ํ ์ ์ผํ ๋ฐฉ๋ฒ์ ์๋์ง๋ง ๋ง์ ์ฌ๋๋ค์ด ๊ทธ๊ฒ์ ์ง๋์น์ง ๋ชปํ๋ ๊ฒ์ด ๊ฑฑ์ ๋ฉ๋๋ค.
์คํํฐ ํจํค์ง์ ํฌํจ๋๋ ํญ๋ชฉ์ ๋ํด ๋ด ์๊ฐ์ ์งง์ ๋ชฉ๋ก์๋ ์์ฉ๊ตฌ ์ถ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค ํ๋(๋๋ ์ฐ๋ฆฌ๊ฐ ๊ตฌ์ถํ ๊ฒ), ์ฝํฌ ๋ฐ ์ฌ๊ฐ์ ๊ฐ์ ์ธ๊ธฐ ์๋ ๋ฏธ๋ค์จ์ด, ์ ์ฉํ ๊ฐ๋ฐ ๋๊ตฌ๊ฐ ํฌํจ๋ฉ๋๋ค. React ๊ด๋ จ ์ฌ์ฉ์๋ฅผ ์ํ ํ์ ์งํฉ ํจํค์ง๊ฐ ์์ ์ ์์ต๋๋ค. ์ฌ์ค, ๊ทธ๊ฒ์ด ํ์ํ์ง ์์๋ณด๊ธฐ ์ํด ์์ํ์ต๋๋ค (RT ๋ถํ๋๋ฆฝ๋๋ค!).
CLI ๋๊ตฌ์ ๊ทธ ๋ชจ๋ ๊ฒ์ ์ฌ์ฉํ์ฌ Create React App๊ณผ ๊ฐ์ ๊ฒฝํ์ ๊ตฌ์ถํ ํ์๊ฐ ์๋ค๊ณ ์๊ฐํฉ๋๋ค. ๊ทธ๋ฌ๋ ๋ ๋์ ๋๋ฒ๊น ๊ณผ ์ ์ ์ฝ๋๋ก ํ๋ฅญํ ๊ฐ๋ฐ ๊ฒฝํ์ ์ ๊ณตํ๋ ์ฆ์ ์ฌ์ฉ ๊ฐ๋ฅํ ๊ฒ์ ๋๋ค.
์ ์ ์! ๋๋ ์ด๊ฒ์ ๋ํด ๋ง์ ์๊ฒฌ๊ณผ ์๋ง์ ๊ฐ์ง๊ณ ์์ต๋๋ค! ๊ทธ๋ฌ๋ ๋๋ ์์ ํ๊ณ ํ ๋ก ์ด ๋จผ์ ์งํ๋๋๋ก ํ ๊ฒ์ ๋๋ค.
์คํ ๊ฐ๋ฅ์ฑ์ด ํ์คํ์ง ์์ ์์๋ฆฌ์คํธ ํญ๋ชฉ ์ค ํ๋๋ createReduxStore()
ํจ์์ ์๋์ผ๋ก ์ถ๊ฐ๋๋ ๊ฐ์๊ธฐ์ฉ ๋ด์ฅ HMR์
๋๋ค. ๋ถํํ๋ Webpack์ ๋ํ ์ง์๊ณผ ๋ช ๊ฐ์ง ์คํ์ ๋ฐ๋ฅด๋ฉด Webpack module.hot.accept()
์ฝ๋ฐฑ์์ ๋ฆฌ๋์ ํ์ผ์ ๋ํ ํ๋์ฝ๋ฉ๋ ๊ฒฝ๋ก๊ฐ ์์ด์ผ ํ๊ธฐ ๋๋ฌธ์ ์ด๊ฒ์ด ์คํ ๊ฐ๋ฅํ์ง ์๋ค๊ณ ํฉ๋๋ค. Parcel ๋๋ ๋ค๋ฅธ ๋ฒ๋ค๋ฌ๊ฐ ์ด๋ฅผ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ๋์ง ํ์คํ์ง ์์ต๋๋ค.
๋ฐ๋ผ์ ๋ชจ๋ ์ฌ๋์ ์ด๊ธฐ ํผ๋๋ฐฑ ์์ฒญ:
๊ฐ๋ฅํ ๋ณํ์ด ์๋ก _๊ฒฉ๋ฆฌ_๋๋ 3๊ฐ์ง ํต์ฌ ํฌ์ธํธ๋ฅผ ์ง์ ํ๊ฒ ์ต๋๋ค.
์ฒซ ๋ฒ์งธ ์์ . ๊ฐ์๊ธฐ ๊ด๋ฆฌ์
1.0 ๋ฐ๋๋ผ(์ฌ๊ธฐ๊ฐ ๋ง๋์?)
1.1 Immer.js
1.2 ์ฝ์ด๋์ค
1.3 100500 ๋ ๋ง์ ํจํค์ง
๋ ๋ฒ์งธ ํฌ์ธํธ. ๋ฏธ๋ค์จ์ด
2.0 ๋ฐ๋๋ผ(์ฌ์ค์ธ๊ฐ์?)
2.1 ์ฌ๊ฐ
2.2 ์ํฝ
2.3 100500๊ฐ ์ด์์ ํจํค์ง.
์ธ ๋ฒ์งธ ํฌ์ธํธ. ๋ฐ์ ํตํฉ
3.0. ๋ฐ๋๋ผ(์ฌ๊ธฐ์ ๊ทธ๋ฐ๊ฐ์?)
3.1. ๋ถ๋ถ๊ณต๊ฐ
3.2 ์ฌ์์ฑ
3.3 100500๊ฐ ์ด์์ ํจํค์ง.
4์, ๋ณด๋์ค, ํฌ์ธํธ
4.0 _boilerplate_์์ ์ด ๋ชจ๋ ๊ฒ์ ํ
์คํธํฉ๋๋ค.
"์ ํํ ๊ฒ"์ ์ ํํ๋ ๊ฒ์ ๋ถ๊ฐ๋ฅํฉ๋๋ค. ์๋ฅผ ๋ค์ด ์ ๋ ์ฌ๊ฐ์ ์ํฝ์ ๋ชจ๋ ์ข์ํ๊ณ ์ฌ์ฉํ์ง๋ง ์ผ๋ถ "์๋ฆฌ ์์์ฆ"๊ณผ ์กฐํฉ์ ๋ํ ๊ถ์ฅ ์ฌํญ์ ์ ๊ณตํ
์๋ฅผ ๋ค์ด ๋๋ถ๋ถ์ redux ์ฌ์ฉ์๋ ๋ฏธ๋ค์จ์ด์ ๋ํด __only__ ์๊ณ ์์ต๋๋ค. ๋ํ ๋ฆฌ๋์๋ก ๋ฌด์ธ๊ฐ๋ฅผ ํ๋ ์์ ๋ถ๋ถ(immutable.js์ ๋ํด ๋ง์ด _๋ค์_), ๋ช ๊ฐ์ง๋ง React ํตํฉ์ ํฅ์์ํต๋๋ค.
์คํํฐ ํคํธ๋ ์ฒ์๋ถํฐ ์์ ํ๊ณ _ํ๋ถํ_ ์ ๊ทผ ๋ฐฉ์์ ๊ตฌ์ถํ๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค. ๋๋ ํ๋ ์ด์์ ์คํํฐ ํคํธ๊ฐ ํ์ํฉ๋๋ค.
Twitter์์ setup/boilerplate์ ๋ฌธ์ ์ ์ ๋ํ ํผ๋๋ฐฑ์ ์์ฒญํ์ต๋๋ค. https://twitter.com/acemarke/status/969040835508604929
ํธ์ํฐ์์ ๋ด ์๋ต ๋ณต์ฌ:
๋๋ ๋ค๋ฅธ ์ฌ๋์๊ฒ redux๋ฅผ ์ํํ๋ '๋น์ ์ ๋ฐฉ์'์ ๋์ ํ ๋ ๋ณต์ก์ฑ์ ๋ํ๊ธฐ ๋๋ฌธ์ redux ์์ฉ๊ตฌ๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ ๋ช ์์ ์ผ๋ก ํผํ์ต๋๋ค. redux๋ฅผ ๋ ์ด์ ๊ฐ๋ฅํ ๊ธฐ์ ๋ก ๋ง๋ค๊ธฐ ์ํด ์ฝ๋๋ฅผ ํตํด ์ํ๋๋ ๋ ๊ท๋ฒ์ ์ธ ๊ท์น์ ์ํฉ๋๋ค.
์ด๋ฅผ ์ํด create-redux-app
์คํ์ผ ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ๊ฐ๋ ๊ฒ์ - ๊ทธ๋ฌ๋ ํ๋ ์์ํฌ๋ณด๋ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ๋ ๋ง์ด ์ค๊ณ๋จ - ํนํ Redux ์ ์ง ๊ด๋ฆฌ์๊ฐ ๊ถ์ฅํ๋ ๋ชจ๋ฒ ์ฌ๋ก ๋ฐ ๊ถ์ฅ ์ฌ๋ก๋ฅผ ๋ช
์์ ์ผ๋ก ๋ณด์ฆํ๋ ์ ์ฅ์๋ฅผ ๊ฐ๋ ๊ฒ์ ๋ช
ํ์ฑ์ ๊ฐํํ๊ณ ์ถ๊ฐํ๋ ๋ฐ ๋จผ ๊ธธ์ ๊ฐ ๊ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค. ์ ์ ํ Redux ์ฌ์ฉ์.
์ฐ๋ฆฌ๋ Reactiflux์์ ์ด๊ฒ์ ๋ํด ์ฝ๊ฐ ์ด์ผ๊ธฐํ๊ณ ์ด ์ค๋ ๋์ ํฌํจ๋๊ธฐ๋ฅผ ์ํ๋ ํตํฉ์ ๋ณต์ฌํ๊ณ ์ถ์์ต๋๋ค. ์ด ์ค ์ผ๋ถ๋ ์ด๋ฏธ @timdorr์ ๋์ดํ ์์ ๊ณผ ๊ฒน์นฉ๋๋ค(๊ทธ๋์ ์ด๊ด์ ์ธ ํ์ธ์ ๋๋ค).
Henrik Joreteg์ redux-bundler์ ๊ฐ์ด ์ด๋ฏธ ์กด์ฌํ๋ ๊ฒ์ ๊ณต์์ ์ผ๋ก ์ง์ํ์ง ์๋ ์ด์ ๋ ๋ฌด์์ ๋๊น?
https://github.com/HenrikJoreteg/redux-bundler
๊ฐ๊ฒฐํ๊ณ (์ข์ ๋ฐฉ์์ผ๋ก) ๋ ๋จ์ ์ด๋ฉฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฐ์์ redux ๊ด๋ จ ๊ธฐ๋ฅ์ ์ฌ์ฌ์ฉํ ์ ์์ผ๋ฉฐ ์ฌ์ ํ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ์ํ ํ๋ฅญํ ์๋ฃจ์ ์ ์ ๊ณตํฉ๋๋ค.
๊ทธ๊ฒ์ ๋งคํน์ ์ผ๋ก ๋ณด์ด๋ ํ๋ก์ ํธ์ด๋ฉฐ, ๋ ์์ธํ ์กฐ์ฌํ๊ณ ์ถ์ง๋ง ์ด ์์ ์ผ๋ก ๋ด๊ฐ ํ๊ณ ์ถ์ ๊ฒ์ ๋ฒ์๋ฅผ ๋ฒ์ด๋ฌ์ต๋๋ค.
์ฌ๊ธฐ์ ๋ด๊ฐ ์ ๋ง๋ก ๋ฌ์ฑํ๊ณ ์ถ์ ๊ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
์ด ๋ ธ๋ ฅ์ ๋ฒ์๋ฅผ ์๋นํ ์ข๊ฒ ์ ์งํ๊ณ ์ถ์ต๋๋ค. ๋๋ ์ง๋ ๋ช ์๊ฐ ๋์ Reactiflux์์ @hswolff ๋ฐ @nickmccurdy ์ ์ฑํ ์ ํ์ผ๋ฉฐ ํ ๋ก ์ ํ๋ฅญํ์ง๋ง ์ฐ๋ฆฌ๋ ์ด๋ฏธ ์ํฉ์ ์ง๋์น๊ฒ ๋ณต์กํ๊ฒ ๋ง๋ค ์ ์๋ 12๊ฐ์ง ์ค๋ณต ์ฌ์ฉ ์ฌ๋ก์ ์์ด๋์ด๋ฅผ ์คํํ์ต๋๋ค.
๋๋ ์ ์ฉํ๊ณ ๊ฐ์น ์๊ณ ์คํ ๊ฐ๋ฅํ _๋ฌด์ธ๊ฐ_๋ฅผ ๋๋ฌด ๋ง์ด ๊ณต์ ํ์ง ์๊ณ ์กฐํฉํ๊ณ ์ถ๊ณ , ๋ค๋ฅธ ๋ ผ์๋ ์์ผ๋ก ํ๊ณ ์ถ์ต๋๋ค(์: Redux "๋ฒ๋ค" ๋๋ "๋ชจ๋"์ ๋ง๋ค๊ธฐ ์ํ API ๋ฑ).
API์ ์ด๊ธฐ ์์ฉ๊ตฌ๋ฅผ ์์ํ๊ธฐ ์ํด ์์ ๊ฒ์ํ ๋ด ๋ชฉ๋ก์ 1-3์ ๋ํ ๊ธฐ๋ณธ ์์ด๋์ด๊ฐ ์์ต๋๋ค.
// #1
export function createStore({
// If an object is given it's passed to combineReducers
// otherwise it's just used directly.
reducer: Object<String, Function> | Function,
// Middleware is built-in and accepts an array of middleware functions.
middleware: Array<MiddlewareFunction>,
// Built-in support for devtools.
// Defaults to NODE_ENV !== production
devTools: boolean,
// Same as current createStore.
preloadedState,
// Same as current createStore.
enhancer,
}) {};
// Re-exported for easy usage.
export function combineReducers() {}
// #2
// Re-export immer as the built-in immutability helper.
import immer from 'immer';
export const createNextState = immer;
// #3
// Export an already written version of createReducer .
// Same thing as https://redux.js.org/recipes/structuring-reducers/refactoring-reducers-example#reducing-boilerplate
export function createReducer() {}
๊ทธ๋, ๋ ๊ทธ๊ฑธ ํํค์ณ. ๊ทธ๋ฐ ๋ค์ ๋ฏธ๋ค์จ์ด ๋ชฉ๋ก์ ๋งจ ์์ ํญ์ thunk()
๋ฅผ ์ถ๊ฐํ๊ฑฐ๋ ๋ฏธ๋ค์จ์ด๋ฅผ ์ง์ ์ ๊ณตํ์ง ์์ ๊ฒฝ์ฐ์๋ง ๊ฐ๋ฅํฉ๋๋ค. ์ฌ์ฉ์๊ฐ ์ฌ๊ธฐ์์ ์ธํธ์๋ฅผ ์ง์ ํ๋ ๊ฒ์ ํ์ฉํ๊ณ ์ถ์ง ์์ ์๋ ์์ต๋๋ค. ์ฐ๋ฆฌ๋ ์ถ๊ฐ ํ ๊ฒ applyMiddleware()
์ด๋ค ๋ฏธ๋ค์จ์ด๊ฐ ์๋ค๋ฉด ์๋์ผ๋กํ๊ณ , ์ฌ์ฉ composeWithDevtools
์์ ๊ธฐ๋ฅ์ redux-devtools-extension
์ ๊ฒฝ์ฐ devTools : true
. ์ด "์ฌ์ด ์ค์ "์ ์ํด ์ฌ์ฉ์๊ฐ ๊ตฌ์ฑํ ์ ์๋ ํญ๋ชฉ์์ "์ธํธ์"๋ฅผ ์ ๊ฑฐํ๊ณ ์ถ์ ์๋ ์์ต๋๋ค.
๊ฐํ์ ์ ๊ฑฐ์ +1.
์ฝํฌ๊ฐ ์๋์ผ๋ก ์ถ๊ฐ๋๋ ์์ ์์ ๊ธฐ๋ณธ ๋ฏธ๋ค์จ์ด๋ฅผ ์ถ๊ฐํ๋ ๋ฐ ์ฌ์ฉํ ๊ธฐ๋ฅ์ ๋ด๋ณด๋ด์ ์ผ์ดํฌ๋ ๋จน๊ณ ๋จน์ ์ ์์ด์ผ ํฉ๋๋ค.
export function createDefaultMiddleware(...additional) {
return [thunk(), ...additional],
}
// Within a user's application
createStore({
// By default it's just createDefaultMiddleware()
// However if you want to add any other middleware you can.
middleware: createDefaultMiddleware(any, other, middleware)
})
๋ค, ๋๋ต์ ์ผ๋ก ์ ๊ฐ ์๊ฐํ๊ณ ์๋ ๊ฒ์
๋๋ค. ๋ด ์ฃผ์ ๊ด์ฌ์ฌ๋ ์ฌ์ฉ์๊ฐ ์ค์๋ก thunk
์ ์์ฒด ์ธ์คํด์ค๋ฅผ ์ ๊ณตํ๋ ค๊ณ ์๋ํ๋์ง ์์๋ด๋ ๊ฒ์
๋๋ค.
๋๋ ์ค๋ ์ ๋ ์ ์ด๊ฒ์ ๊ฒ ์ข ๊ฐ์ง๊ณ ๋๊ธฐ๋ก ํ๋ค. ๋ค์์ ์ฒซ ๋ฒ์งธ ์ปท์ ๋๋ค. ์๊ฐ?
// configureStore.js
import {createStore, compose, applyMiddleware, combineReducers} from "redux";
import { composeWithDevTools } from 'redux-devtools-extension';
import createNextState from "immer";
import isPlainObject from "./isPlainObject";
import thunk from "redux-thunk";
const IS_DEVELOPMENT = process.env.NODE_ENV !== "production";
export function createDefaultMiddleware(...additional) {
return [thunk, ...additional];
}
export function configureStore(options = {}) {
const {
reducer,
middleware = createDefaultMiddleware(),
devTools = IS_DEVELOPMENT,
preloadedState,
} = options;
let rootReducer;
if(typeof reducer === "function") {
rootReducer = reducer;
}
else if(isPlainObject(reducer)) {
rootReducer = combineReducers(reducer);
}
else {
throw new Error("Reducer argument must be a function or an object of functions that can be passed to combineReducers");
}
const middlewareEnhancer = applyMiddleware(...middleware);
const storeEnhancers = [middlewareEnhancer];
let finalCompose = devTools ? composeWithDevTools : compose;
const composedEnhancer = finalCompose(...storeEnhancers);
const store = createStore(
rootReducer,
preloadedState,
composedEnhancer
);
return store;
}
export function createReducer(initialState, actionsMap) {
return function(state = initialState, action) {
const {type, payload} = action;
return createNextState(state, draft => {
const caseReducer = actionsMap[type];
if(caseReducer) {
return caseReducer(draft, payload);
}
return draft;
});
}
}
export {createNextState, combineReducers};
๊ทธ๋ฆฌ๊ณ ํ์ ์์ ํ ์ผ ์ฑ:
import {configureStore, createReducer} from "./configureStore";
const ADD_TODO = "ADD_TODO";
const TOGGLE_TODO = "TOGGLE_TODO";
const SET_VISIBILITY_FILTER = "SET_VISIBILITY_FILTER";
function setVisibility(state, newFilterType) {
return newFilterType;
}
const visibilityReducer = createReducer("SHOW_ALL", {
[SET_VISIBILITY_FILTER] : setVisibility
});
function addTodo(state, newTodo) {
state.push({...newTodo, completed : false});
}
function toggleTodo(state, payload) {
const {index} = payload;
const todo = state[index];
todo.completed = !todo.completed;
}
const todosReducer = createReducer([], {
[ADD_TODO] : addTodo,
[TOGGLE_TODO] : toggleTodo
});
const preloadedState = {
todos: [{
text: 'Eat food',
completed: true
}, {
text: 'Exercise',
completed: false
}],
visibilityFilter : 'SHOW_COMPLETED'
};
const store = configureStore({
reducer : {
todos : todosReducer,
visibilityFilter : visibilityReducer,
},
preloadedState,
});
const exercise1 = store.getState().todos[1];
store.dispatch({type : "TOGGLE_TODO", payload : {index : 1}});
const exercise2 = store.getState().todos[1];
console.log("Same object: ", exercise1 === exercise2);
store.dispatch({type : "SET_VISIBILITY_FILTER", payload : "SHOW_COMPLETED"});
console.log(store.getState());
๋๋ ์ด๊ฒ์ด ์ด ์ค๋ ๋์์ ๋ ผ์๋๋ lib์ ๊ฒฌ๊ณ ํ ์์์ด์ ํ๋ฅญํ ์์์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค. ์ ์ ์ํ๋ ๊ธฐ๋ฅ ๋ชฉ๋ก์์ ํฌ์ธํธ
์ด๊ฒ ์์ ๋ฐ๋ณตํ๋ ๊ฒ์ ํ๋ฅญํ ๊ฒ์ด์ง๋ง ์ด๊ฒ์ ๊ฒฌ๊ณ ํ ํ ๋์ ๋๋ค.
๊ตฌํ์ ์ง์คํ๊ธฐ ๋ณด๋ค๋ DX์ ์ง์คํ์ผ๋ฉด ํฉ๋๋ค. ๋ด๋ณด๋ด๊ธฐ/API๋ ๋ฌด์์ด๋ฉฐ ์ด๋ป๊ฒ ์ฌ์ฉ๋ฉ๋๊น? ๊ตฌ์ฑ๋ง ์ดํด๋ณด๊ณ ์ฌ๋๋ค์ด ์์ ์ ์ด๋ป๊ฒ ์ฌ์ฉํ๋์ง ์ดํด๋ณผ ์ ์๋ ์ข์ ๊ธฐํ๋ผ๊ณ ์๊ฐํฉ๋๋ค. ์์์ ์์ด๋์ด:
์ํ ์ถ๋ ฅ๊ณผ ํจ๊ป ๊ฐ์๊ธฐ ๋ฐ ์์ ์ ๋งค์ฐ ์ฝ๊ฒ ์์ผ๋ก ๋ง๋ค ์ ์์ต๋๋ค. ์ด๊ฒ์ ๊ฑฐ์น ์ง๋ง ๊ธฐ๋ณธ ์์ด๋์ด๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
import { createStore, createActionPack, combineActionPacks } from 'redux/starter'
const counter = createActionPack({
increment: counter => counter + 1,
decrement: counter => counter - 1,
set: (_, value) => value
}, 0)
const posts = createActionPack({
load: async () => await fetch('/posts'),
create: async (state, text) => state.push(await fetch('/posts/new', { body: { text } }))
}, [])
const store = createStore(
combineActionPacks(
counter,
posts
)
)
store.dispatch(counter.increment())
store.dispatch(counter.set(42))
await store.dispatch(posts.load())
await store.dispatch(posts.create('First!'))
์ด๊ฒ์ ๋ด๊ฐ ์ด๋ค ๋ฐฉ์์ผ๋ก๋ ํ๋งค๋์ง๋ ์์ง๋ง React Router์ ํ์คํ ๋ฆฌ ์ฑ๊ธํค์ด ์์๋ ์์ ์ ์๊ฐํ๊ณ ์์์ต๋๋ค. ์๋ฒฝํ์ง๋ ์์์ง๋ง ์ด๋ ์ ๋ ๊ฐ์น๋ฅผ ์ ๊ณตํ์ต๋๋ค.
import { store, configureStore } from 'redux/starter'
configureStore(reducer, middleware, initialState)
store.dispatch(someAction())
store.getState()
import
๋ฅผ ํตํ ๊ตฌ์ฑ ๊ฐ๋ฅ๋๋ ๋ง์ง๋ง์ ์ํด ๋์ ์๋ฑํ ๊ฒ์ ์๋ ๊ฒ์ด๋ค. ๊ทธ๋ฌ๋ ํ์ผ์ ๊ฐ์ ธ์์ ๊ตฌ์ฑ์ ํ์ฉํ๋ค๋ฉด ์ด๋จ๊น์? ์ง์ ๋ถํ๊ฑฐ๋ ๋ฌธ์ ๊ฐ ๋๋ ๋ฐฐํ์์ ์ ์ญ ์ ๋ฌ์ด ํ์ํฉ๋๋ค. ๊ทธ๋ฌ๋ ๋ค์ ๋งํ์ง๋ง ์ด์ ์ ์ฐ๋ฆฌ ํธ์ด ์๋๋ผ ์ฌ์ฉ์์ ๋๋ค.
import { createStore } from 'redux/starter'
import 'redux/starter/devtools'
import 'redux/starter/logger'
import 'redux/starter/immutable'
// OR!
import { createStore } from 'redux/starter/developer'
import { createStore } from 'redux/starter/production'
๋ ๋ฒ์งธ ์์์๋ ๋น๋ ๋๊ตฌ์์ ํด๋น ํจํค์ง์ ๋ณ์นญ์ ์ง์ ํ๊ฑฐ๋ React๊ฐ ํ๋
์ข์, ์ง๊ธ์ ๊ทธ๊ฒ ๋๋ถํฐ์ผ. ๋ค์ ๋งํ์ง๋ง ์ ๋ ์ฌ์ฉ์๋ฅผ ๋จผ์ ์๊ฐํ๊ณ ์ถ์ต๋๋ค. ์ด๊ฒ์ ๊ตฌํํ๊ธฐ ์ํด ์ฐ๋ฆฌ๊ฐ ํด์ผ ํ๋ ๋๋ฝ๊ณ ์ถ์ ํ ํต์ ๋ฌด์์ด๋ ๊ด๋ จ์ด ์์ต๋๋ค. ์์ ์ ์์ฑ๋ ์ฝ๋๊ฐ ์ ๊ณ ๊ตฌ์ฑ์ด ๋ ํ์ํ ํ๋ฅญํ DX์ ๋๋ค.
์ง๊ธ๊น์ง ์ด๋ฌํ ์์ด๋์ด๋ฅผ ์ฌ๋ํฉ๋๋ค. ์ด๊ฒ์ด ๋ฐํ์ง ๊ฒ์ด ๋ฌด์์ด๋ ๋์ ์ ์ผํ ์์์ ๋ ๋ฎ์ ์์ค์ ํ์ค Redux API์ ๋ํ ์ฐ์ํ ์ก์ธ์ค์ ๋๋ค. ์ฌ๋๋ค์ด ๋ง์ถคํํ๊ฑฐ๋ ๋ฐฐ์ถํ ์ ์๋ ์์ฐ์ค๋ฌ์ด ๊ฒฝ๋ก๊ฐ ํ์ํฉ๋๋ค. ๊ทธ๊ฒ์ด ๋ฉฐ์น ์ด๋ 1๋ ์ด๋ 2๋ ์ด๋ ๊ฐ์ ๊ฐ๋จํด์ผ ํฉ๋๋ค. Lock-in์ ๋ด๊ฐ ๋ณธ ๋ฌธ์ ์ค ํ๋์ ๋๋ค(Jumpstate๋ฅผ ์ฌ์ฉํ ๋ด ์์ ์ ์๋์ Rematch์ ๊ฐ์ ์ต์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์). ์ฐ๋ฆฌ๊ฐ ๊ทธ๊ฒ์ ํผํ ์์์์๋ก ์ฌ๋๋ค์ ์ ์ ๋ ์ข์ ๋ง์ ๊ฐ๊ฒ ๋ ๊ฒ์ ๋๋ค :)
์, "์ก์ ํฉ"๊ณผ ๊ฐ์ ์์ ์ ์ํํ๋ ๊ฝค ๋ง์ ์ ํธ๋ฆฌํฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ณด์๊ณ (์ ์ด๋ "๋ฆฌ๋์ ์์ฑ, ํค๋ฅผ ์ก์ ์ ํ ๋ฐ ์ก์ ์์ฑ๊ธฐ๋ก ์ ํ" ์ธก๋ฉด์์) ๋์ง๊ธฐ๋ฅผ ๊ณ ๋ คํ๊ณ ์์์ต๋๋ค. ์ถ๊ฐ ํญ๋ชฉ์ผ๋ก - ์์ง ๊ฑฐ๊ธฐ์ ๋๋ฌํ์ง ๋ชปํ์ต๋๋ค. "combineActionPack" ์ธก๋ฉด์ด ํ์คํ์ง ์์ต๋๋ค.
์ด์ ฏ๋ฐค @hswolff ์ ์ถ๊ฐ ํ ๋ก ์ ์ ํ๊ธฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ถ๊ฐ/๋ค์ ๋ด๋ณด๋ด๋ ๊ฒ์ ๊ณ ๋ คํ๊ณ ์ถ์ต๋๋ค.
import createSelector from 'selectorator';
// selector created with single method call
const getBarBaz = createSelector(['foo.bar', 'baz'], (bar, baz) => {
return `${bar} ${baz}`;
});
const selectTodos = state => state.todos
์ ๊ฐ์ด ์์ผ๋ก ์ด "๊ฐ๋จํ ์
๋ ฅ" ์ ํ์๋ฅผ ๋ง์ด ์ค์ด๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค.
์ ํ๊ธฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ถ๊ฐํ๋ ์ด์ ์ด ์๋์ง ์ ๋ชจ๋ฅด๊ฒ ์ต๋๋ค. ์ฐ๋ฆฌ๋ ๋ํ ๊ทธ๊ฒ์ ์ํด ํ์ฑํ๋๋ ์ํ ํํ์ ๋ํ ์๊ฒฌ์ ์ ๊ณตํด์ผ ํ ๊ฒ์ ๋๋ค.
์ฌ์ฉ์๊ฐ package.json
์ ์ค์นํด์ผ ํ๋ ํญ๋ชฉ์ด ํ๋ ์ค์ด๋ค๊ธฐ ๋๋ฌธ์ ์ ์ด๋ ๋ถ๋ถ์ ์ผ๋ก ๊ทธ๋ ์ต๋๋ค.
์ ํ๊ธฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ํ๋ฅญํ ๊ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค.
๊ด๋ จ์ฑ: apollo-boost
์คํํฐ ํคํธ ์ ๋ํ ์ต๊ทผ ๊ธฐ์ฌ
mapStateToProps
๊ฐ Array
์ผ ๋ reselect (๋๋ ์ ์ฌํ ์ ํ๊ธฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ)๋ฅผ ์ฌ์ฉํ๋๋ก react-redux
์ connect
์ API๋ฅผ ํ์ฅํ ์ ์๋ค๋ฉด ์ ํ์์ ์ฌ์ฉ์ ๊ถ์ฅํ๊ณ ํธํ์ฑ์ ์์์ํค์ง ์๊ณ ๋งค์ฐ ํธ๋ฆฌํ๊ฒ ๋ง๋ญ๋๋ค. ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ React ๋๋ react-redux
์ ๋ฐ๋์ ๊ฒฐํฉ๋์ด์ผ ํ๋ค๊ณ ์๊ฐํ์ง๋ ์์ง๋ง react-redux
์ต์
์ ํตํด ํ์ฅ์ฑ์ ์ฒ๋ฆฌํ๊ฑฐ๋ react-redux
์คํํฐ ํคํธ๋ฅผ ๋ํํ๋ ๋ค๋ฅธ ํจํค์ง๋ฅผ ์ ๊ณตํ ์ ์์ต๋๋ค.
๋ค, ์ ๋ ์ด ์ด๊ธฐ MVP๋ฅผ ์ํด React-Redux๋ก ์๋ฌด ๊ฒ๋ ํ ์๊ฐ์ด ์์ต๋๋ค.
์ด ๊ฒฝ์ฐ Redux ์์ค์์ ์ ํ๊ธฐ์ ๋ํ ์ถ์ํ๋ฅผ ์ถ๊ฐํ๋ ์ข์ ๋ฐฉ๋ฒ์ด ์์ต๋๊น? ์๋๋ฉด ์ด๊ฒ์ด react-redux ์์์๋ง ํจ๊ณผ์ ์ผ๋ก ํ ์ ์๋ ๊ฒ์ ๋๊น? ๋ฌธ์ ๋ ์ด๊ฒ์ด react-redux์ ํธํ๋์ง ์๋ ๊ฒ์ ์ํ์ง ์๋๋ค๋ ๊ฒ์ ๋๋ค. ๊ทธ๋์ ์ด๊ฒ์ด ๊ฐ๋ฅํ์ง ์๋ค๋ฉด ์ง๊ธ์ ์ ํ๊ธฐ๋ฅผ ๋ฒ๋ ค์ผ ํฉ๋๋ค.
์คํ ์ด API๋ฅผ ๊ตฌํํ๋ ํ react-redux์ ํธํ๋ฉ๋๋ค. ์ฐ๋ฆฌ๋ ๊ทธ API๋ฅผ ๊นจ๋ ค๋ ๊ฒ์ด ์๋๋ผ DX๋ฅผ ๊ฐ์ ํ๊ธฐ๋ง ํ๋ฉด ๋ฉ๋๋ค.
๊ทธ๊ฒ์ ์๋ฏธ๊ฐ ์์ต๋๋ค. ๋๋ react-redux ์ธ๋ถ์์ ์ ํ๊ธฐ๋ฅผ ์ฌ์ฉํ์ง ์์์ผ๋ฏ๋ก ์ฌ๊ธฐ์์ Redux ์์ฒด๋ฅผ ๊ตฌ์ฑํ๋ ๋ฐ ์ ์ฉํ ์ ์๋์ง ๊ถ๊ธํฉ๋๋ค.
@timdorr ๋ ์ฌ์ด ๋ฆฌ๋์/์ก์ ์์ผ๋ก ํํ๋ ์๊ตฌ์ +1. ๋ํ ๋ฆฌ๋์, ์ก์ ์์ฑ๊ธฐ ๋ฐ ์ ํ๊ธฐ๋ฅผ ์์ฑํ๋ ๊ฒ์ด ํจ์ฌ ๋ ์ฆ๊ฒ๊ณ ์ฌ์ฉํ๊ธฐ ์ฌ์ด ๊ฒฝํ์ด ๋๋๋ก redux ๋ชจ๋(์ผ๋ช ์ค๋ฆฌ ํจํด)์ ๋ ์ฝ๊ฒ ์์ฑํ ์ ์๋ ๋ฐฉ๋ฒ์ ์๊ฐํ๊ณ ์ถ์ต๋๋ค.
๋๋ถ๋ถ์ ์ฌ๋๋ค์ ํ๋ณตํ๊ฒ ํ๋ ๊ทธ ๋ฌธ์ ์ ๋ํ ํด๊ฒฐ์ฑ ์ ์ฐพ๊ธฐ ์ํด์๋ ์กฐ๊ธ ๋ ๋ง์ ์์ ๊ฑฐ ์ดํ์ด ํ์ํ๋ฉฐ ํ์ ๋ฒ์ ์ ์ถ๊ฐํ ์ ์๋์ง ๊ถ๊ธํฉ๋๋ค. ํ์ด ์ฃผ๋ค.
@markerikson ์ด ๊ทธ์ ์ฝ๋ฉํธ์์ ์์ฑํ ๊ฒ์ ์ด๋ฏธ ์์ฉ๊ตฌ๋ฅผ ์๋นํ ์ค์ด๊ณ ํ๋ฅญํ ์ด๊ธฐ ์ํํ์ ๋ง๋ค ์ ์์ ๊ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค.
๊ทธ ํ, ์ฐ๋ฆฌ๋ ๋ฒ๊ฑฐ๋ก์ด Redux์ ๋ค๋ฅธ ์ธก๋ฉด(redux/action/selector ์์ฑ)์ ๋ค๋ฃฐ ์ ์์ต๋๋ค.
๋ชจ๋ ๋ฌธ์ ๋ฅผ ๋ฏธ๋ฆฌ ํด๊ฒฐํ๋ ค๊ณ ํ๋ฉด ์ด๋ค ํํ๋ก๋ ๊ฐ์์ ์ธ ์ง์ ์ ์ด๋ฃจ๋ ๋ฐ ๋ฐฉํด๊ฐ ๋ ๊ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค.
์ถฉ๋ถํ ์ค๋น๋์๋ค๊ณ ์๊ฐ๋๋ฉด ์ ์ฅ์๋ฅผ ์์ํ์ฌ ์์ ์ฝ๋๋ก ์ด ์ค์ ์ ํ ์คํธํ๊ณ ์ฝ๊ฐ์ dogfood(๋๋ monorepo์ ๊ธฐ๋ฅ ๋ถ๊ธฐ์ ์๋ ํจํค์ง๋ฅผ ํ ์คํธํ ์ ์์ต๋๋ค. PR์ ํตํด ํ์ ).
ํ์ ํ๋. ์ค๋์ ์กฐ๊ธ ์๋ค๊ฐ ์ ๋ฆฌํ ์ ์๋์ง ์์๋ณด๊ฒ ์ต๋๋ค.
๋ค๋ฅธ ์ ์ฅ์๊ฐ ํ์ํ์ง ์์ต๋๋ค. ์ด๊ฒ์ ํ์ฌ ๊ฒ ์์ ์กด์ฌํ ๊ฒ์ ๋๋ค. ๋ฌด์์ด๋ ๋จผ์ ํ๋ณดํ์ธ์.
์ด๊ฒ์ ๋ณ๋์ ๊ฐ์ ธ์ค๊ธฐ๋ก ๊ธฐ๋ณธ redux
ํจํค์ง์ ์ผ๋ถ์ฌ์ผ ํฉ๋๊น(์์ ํ ์ญํธํ ๊ฐ๋ฅ) ์๋๋ฉด ์ฌ๋ฌ ํจํค์ง๊ฐ ์๋ ๋จ์ผ ์ ์ฅ์๋ฅผ ์ ํธํฉ๋๊น? ์ ์๋ก ์ถฉ๋ถํ๋ค๊ณ ์๊ฐํฉ๋๋ค. ํ์ผ์ด ๋๋ฌด ์ปค์ง๋ฉด ์ ํจํค์ง๋ฅผ ๋ง๋ค์ง ์๊ณ ํญ์ ๋ค๋ฅธ ํ์ผ ๋ด๋ณด๋ด๊ธฐ๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋๋ ์ด๊ฒ์ ๋ณ๋์ ๋ฆฌํฌ์งํ ๋ฆฌ/ํจํค์ง๋ก ์์ํ์ฌ ์ค์ ๋ก ๊ฐ์ง๊ณ ๋๊ณ ์ถ์ต๋๋ค.
๋์ค์ ๋ค์ ๋ณํฉํ๋ฉด ์ค๋ฅ๊ฐ ๋ฐ์ํ๊ธฐ ์ฌ์ฐ๋ฏ๋ก ์ด ๋ฆฌํฌ์งํ ๋ฆฌ์์ ๊ธฐ์กด ๋๊ตฌ ์ค์ ์ ์ฌ์ฉํ๋ ๊ฒ์ด ๋ ์ฌ์ธ ์ ์์ต๋๋ค. ๋ํ ์ด React๋ฅผ ํน์ ํ๊ฒ ๋ง๋ค์ง ์๊ธฐ ๋๋ฌธ์ ๋ค๋ฅธ ๊ตฌ๋ฌธ ์ง์์ด ํ์ํ์ง ์์ ์๋ ์์ต๋๋ค.
์ฌ์ ๊ตฌ์ฑ์ด ํฌํจ๋ ํ๋์ ๋จ์ผ ํ์ผ์ธ ๊ฒฝ์ฐ ์ฌ๊ธฐ์ ์ ์งํ๋ ๊ฒ์ด ๊ฐ์ฅ ์ฝ์ต๋๋ค. ์ข ์์ฑ ๋๋ฌธ์ ๋ณ๋์ ํจํค์ง์ฌ์ผ ํฉ๋๋ค. ์ฐ๋ฆฌ๋ ๊ธฐ์กด ์ฑ์ ๊ทธ๊ฒ๋ค๋ก ์ฑ์ฐ๊ณ ์ถ์ง ์์ต๋๋ค.
๋ค์ ๋งํ์ง๋ง, ๋ชจ๋
ธ๋ ํฌ๋ก ๊ฐ ํ์๋ ์๋ค๊ณ ์๊ฐํ์ง๋ง ํ๋ ์ด์์ ๋น๋๋ฅผ ์์ํ๋ฉด ํน์ ํจํค์ง ๋น๋์ฉ ํด๋๋ฅผ ๊ฐ์ง ์ ์์ต๋๋ค. ํ์ฌ๋ก์๋ ์์ฒด package.json์ด ์๋ starter
ํด๋๋ง ์์ผ๋ฉด ๋ฉ๋๋ค.
redux ์์ฒด์ ๋ก์ปฌ ์ฝ๋๋ง ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ์ด ํจํค์ง๋ฅผ ๊ธฐ๋ณธ redux ํจํค์ง์ ๋ก์ปฌ๋ก ์ ์งํ๋ ์์ด๋์ด๊ฐ ์ข์ต๋๋ค. ์ฌ๊ธฐ์ ํํ๋ ์์ด๋์ด๋ฅผ ์ง์ํ๊ธฐ ์ํด ์ธ๋ถ ์ข ์์ฑ์ ๊ฐ์ ธ์ค๊ธฐ ์์ํ๋ฉด ๋ ์ฃผ์ ํฉ๋๋ค.
immer, thunk/promise/saga ๋ฐ reselect์ ๊ฐ์ ์ผ๋ถ ์ธ๋ถ ์ข
์์ฑ์ ์ฌ๊ธฐ์์ ์ฐ๋ฆฌ์ ๋ชฉํ์ ๋งค์ฐ ์ค์ํ๊ณ ์์์๋ฅผ ์ํ ์ถ๊ฐ ์ข
์์ฑ์ด ๊ฐ์น๊ฐ ์๋ค๊ณ ์๊ฐํฉ๋๋ค. ํ์ง๋ง ๊ธฐ๋ณธ redux
ํจํค์ง ์์ฒด์ ๋ํ ์ข
์์ฑ์ ์ํ์ง ์์ ์๋ ์์ต๋๋ค. .
๊ทธ๋์, ์ด... ๋ด๊ฐ ๊ฐ์ ํ ๊ฐ์ง:
์ด์ ์ค๋ํซ๊ณผ ๋ค๋ฅธ ์ :
enhancers
๊ตฌ์ฑ ์ต์
์ ๋ฃ์์ต๋๋ค.selectorator
์์กด์ฑ์ ๋ด ๋ณด๋ธ createSelector
์๊ฐ?
์ง๋ ๋ช ์ฃผ ๋์ Redux(๋ฐ React)๋ฅผ ๋ฐฐ์ด ์ฌ๋์ผ๋ก์ ์ต์ข ์ ํ์ ๋ณด๊ณ ์ถ์ต๋๋ค. ๋ด ์ฝ๋์์ ์ ๋ฆฌํ ๋ด์ฉ์ด ์์ฒญ๋๊ฒ ๋ง์ ๊ฒ์ด๋ผ๊ณ ํ์ ํฉ๋๋ค.
๐ ๐
๋ฐ๋ผ์ redux ์ฌ์ฉ์ ๋จ์ํํ๋ ๊ฒ์ด ๊ธด ์์ด๋์ด๋ผ๋ฉด 2๊ฐ์ ์๊ฐ์ ์ ์ํ ์ ์์ต๋๋ค.
๋ง ๊ทธ๋๋ก expect(mapStateToProps(state)).toEqual(mapStateToProps(state))
์ ๋ด์ฅ ํจ์๋ฅผ ์ถ๊ฐํฉ๋๋ค. ์ฌ๋๋ค์ด ๋ ๋์ ์ฝ๋๋ฅผ ๋ง๋ค๋๋ก ๊ฒฉ๋ คํ๊ธฐ ์ํด์์
๋๋ค. ๋๋ ์ด๋ฐ ํ
์คํธ๋ฅผ ๋ณธ ์ ์ด ์์ง๋ง _์์ํ์ง ์์_ mapStateToProps๋ redux ๋ฌธ์ ์ค ํ๋์
๋๋ค.
memoize-state ์ ๊ฐ์ ์ฑํ์ ๊ณ ๋ คํ์ญ์์ค. ์ ํ์๋ฅผ ์ํ Immer.js์ ๊ฐ์ต๋๋ค. ์์ - ๊ณ ๊ฐ์ ์ ํธํ๋ ํ์์ผ๋ก mapStateToProps ๋๋ ์ ํ๊ธฐ๋ฅผ ์์ฑํ๊ณ ๋ฉ๋ชจํํ ์ ์์ต๋๋ค. ์ธ์คํด์ค ๊ฐ์ "๊ณตํต" ๋ฉ๋ชจ๋ฅผ ์์ง ์๊ณ "์ฌ๋ฌ ๊ตฌ์ฑ ์์ ์ธ์คํด์ค์ ๊ฑธ์ณ ์ํ๊ณผ ์ ํ๊ธฐ ๊ณต์ "๋ก ์ด ์ฌ์ ํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์๋ ์์ต๋๋ค. ๋ด์ฉ์ ๋ ๋ฒ ๋ฉ๋ชจ ํ์ญ์์ค.
๊ทธ๋๋ ์์์ ๋ ผ์ํ ๊ฒ์ฒ๋ผ ์ด๊ฒ์ React์ ๋ฌด๊ดํ ์คํํฐ ํจํค์ง์ ์๋ ๊ฒ๋ณด๋ค react-redux์ ๊ฐ๊น์ต๋๋ค.
์ด๊ฒ์ ์ ๋ง ๋ฉ์ง๋ค!
ํ์ง๋ง ํ ๊ฐ์ง ์์ฒญ/ํผ๋๋ฐฑ์ด ์์ต๋๋ค. Immer๊ฐ ์์์ ์ผ๋ก ์ฌ์ฉ๋์ง ์์์ผ๋ฉด ์ข๊ฒ ์ต๋๋ค.
Immer๋ ํ๋ฅญ ํฉ๋๋ค. ์ ๊ฐ ๊ฐ์ฅ ์ข์ํ๋ ์ ํธ๋ฆฌํฐ ์ค ํ๋๊ฐ ๋์์ต๋๋ค. ํ์ง๋ง ๋ช
์์ ์ผ๋ก ์ฌ์ฉํ ๋๋( produce(baseState, draftState => ...
), ๊ทธ๊ฒ์ ์ต์ํ์ง ์์ ๋ค๋ฅธ ์ฌ๋๋ค์ด ๋ด ์ฝ๋๋ฅผ ๋ณผ ๋ ๊ฑฑ์ ์ด ๋๊ณ , ๋ด๊ฐ Immer ์ด๋ฅ๋ ฅ ๋๋ฌธ์ ์ด ๋ณ๊ฒฝ ์์
๋ง ํ ์ ์๋ค๋ ๊ฒ์ ๊นจ๋ซ์ง ๋ชปํฉ๋๋ค.
API๊ฐ ์ง๊ธ ๋ณด์ด๋ ๋ฐฉ์์ผ๋ก ์ ์ฌ์ฉ์๊ฐ redux ์ํ๊ฐ ๋ณ๊ฒฝ ๋ถ๊ฐ๋ฅํด์ผ ํ๋ค๋ ๊ฒ์ ๊นจ๋ซ์ง ๋ชปํ๋ ๊ฒ์ ์์ํ ์ ์์ต๋๋ค. ๋๋ ๊ทธ๋ค์ด ์ด ์คํํฐ ํคํธ ์์ด Redux๋ฅผ ์ฌ์ฉํ๋ ค๊ณ ํ ๋ ์คํด๊ฐ ๊ทธ๋ค์ ์ฌํ๊ฒ ๋ฌผ๋ฆด ๊ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค.
createNextState
๋ ์ด๋ฏธ ๋ด๋ณด๋ด๊ธฐ์ด๋ฏ๋ก ์ฌ์ฉ์๊ฐ ๋ช
์์ ์ผ๋ก ์ฌ์ฉํ๋๋ก ๊ถ์ฅํ์ง ์๋ ์ด์ ๋ ๋ฌด์์
๋๊น?
import {createReducer, createNextState} from "@acemarke/redux-starter-kit";
function addTodo(state, newTodo) {
return createNextState(state, draftState => {
draftState.push({...newTodo, completed : false});
});
}
( createNextState
์ฉ๋๋ฅผ ์๋ชป ์ดํดํ๋ค๋ฉด ์ฌ๊ณผ๋๋ฆฝ๋๋ค! ์ ํ ํํค์น์ง ์์์ต๋๋ค)
https://github.com/markerikson/redux-starter-kit/issues/5๋ฅผ ์ฐธ์กฐ
API๊ฐ ์ง๊ธ ๋ณด์ด๋ ๋ฐฉ์์ผ๋ก ์ ์ฌ์ฉ์๊ฐ redux ์ํ๊ฐ ๋ณ๊ฒฝ ๋ถ๊ฐ๋ฅํด์ผ ํ๋ค๋ ๊ฒ์ ๊นจ๋ซ์ง ๋ชปํ๋ ๊ฒ์ ์์ํ ์ ์์ต๋๋ค. ๋๋ ๊ทธ๋ค์ด ์ด ์คํํฐ ํคํธ ์์ด Redux๋ฅผ ์ฌ์ฉํ๋ ค๊ณ ํ ๋ ์คํด๊ฐ ๊ทธ๋ค์ ์ฌํ๊ฒ ๋ฌผ๋ฆด ๊ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค.
์ ์๊ฐ์๋ https://github.com/reactjs/redux/issues/2858 ๋๋ฌธ์ ์ด ํจํค์ง๊ฐ ์์ฑ๋์์ ๋ Redux๋ฅผ ์ง์ ์ฌ์ฉํ์ง ์๋ ๊ฒ์ด ์ข์ต๋๋ค
createNextState๋ ์ด๋ฏธ ๋ด๋ณด๋ด๊ธฐ์ด๋ฏ๋ก ์ฌ์ฉ์๊ฐ ๋ช ์์ ์ผ๋ก ์ฌ์ฉํ๋๋ก ๊ถ์ฅํ์ง ์๋ ์ด์ ๋ ๋ฌด์์ ๋๊น?
๋์ ์๊ฐ์ ์๋์ง๋ง, ํนํ ์์ค ์ฝ๋๋ฅผ ์์ฑํ์ง ์๊ณ immer ์ถ๊ฐ๊ฐ ์ญํธํ๋๊ธฐ ๋๋ฌธ์ ์ฌ๊ธฐ์์ ์์์ ์ธ ๊ฒ์ ๋ ์ ํธํ๋ค๊ณ ์๊ฐํฉ๋๋ค.
libs
immer.js
libs
์ ๊ฐ์ด store
์๊ตฌ ์ฌํญ์ ์กด์คํ๋ ๊ฒ์ผ๋ก ๊ตฌ์ฑ๋์ด ์์ต๋๋ค.
์ฐ๋ฆฌ๋ ๋ชจ๋ ์ ์ฅ์๋ฅผ ๋ณ๊ฒฝํ ์ ์๋ค๋ ๊ฒ์ ์๊ณ ์์ผ๋ฏ๋ก newState
์ธ์คํด์ค๋ฅผ previousState
๋ํด ( ===
) ํ์ธํ๋ ์ ํจ์ฑ ๊ฒ์ฌ ๋ฉ์ปค๋์ฆ์ ํจ์ฌ ๋ ์ ํธํฉ๋๋ค. ๋์ผํ ์ธ์คํด์ค์ธ ๊ฒฝ์ฐ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
์ด๋ฐ ์์ผ๋ก ๋ชจ๋ ์ฌ๋์ด store
์ ๊ท์น๊ณผ ์๊ตฌ ์ฌํญ์ ๋ฐฐ์ฐ๋๋ก ๊ฐ์ ๋ฉ๋๋ค.
์ถ์ : ์ ๋ immer
์ ์ด์ ์ ์ง์ ์ผ๋ก ์ดํดํ๊ณ ์์ผ๋ฉฐ ๊ทธ๊ฒ์ ๋ํด ์ ํ ๋ฐ๋ํ ๊ฒ์ด ์์ต๋๋ค. ๊ทธ๋ฌ๋ ์ฐ๋ฆฌ๋ ์ฌ๋๋ค์ด ๋ง์นจ๋ด ๊ฐ๋
์ ์ดํดํ๋ ์์ ์ ๋๋ฌํ๊ณ ์์ต๋๋ค. ์ด๋ ํผ๋์ ๊ฑฐ๋ํ ๊ทผ์์ ์์ฑํ๊ณ ๊ธฐ์ ์ ์ผ๋ก ๋ค์๊ณผ ๊ฐ์ต๋๋ค. ๋ฒค์น๋งํนํ๋ฉด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋์จํ๊ฒ ํ๊ธฐ ์ํด ๋ณต์ก์ฑ์ ์ถ๊ฐํ๋ ๊ฒ ์ธ์๋ ์๋ฌด๊ฒ๋ ํ์ง ์์ ๊ฒ์
๋๋ค.
๊ฐ์ธ์ ์ธ ์ ์:
logger
, devTools
๋ฐ Thunk
๋ Starter
๊ธฐ๋ณธ๊ฐ์ผ๋ก ์ถ๊ฐ๋์ด์ผ ํ๋ฉฐ ๋๋จธ์ง๋ ๊ฐ์ธ์ ์ธ ์ ํ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค.
์ฐ๋ฆฌ ๋ชจ๋๋ ์ ์ฅ์๋ฅผ ๋ณ๊ฒฝํ ์ ์๋ค๋ ๊ฒ์ ์๊ณ ์์ผ๋ฏ๋ก newState ์ธ์คํด์ค๋ฅผ previousState ( === )์ ๋ํด ํ์ธํ๊ณ ๋์ผํ ์ธ์คํด์ค์ธ ๊ฒฝ์ฐ ์ค๋ฅ๋ฅผ ๋ฐ์์ํค๋ ์ ํจ์ฑ ๊ฒ์ฌ ๋ฉ์ปค๋์ฆ์ ํจ์ฌ ๋ ์ ํธํฉ๋๋ค.
๋์์ ๋ฐ๋ผ ์ํ๋ฅผ ๋ณ๊ฒฝํ์ง ์์ผ๋ ค๋ ๊ฒฝ์ฐ๊ฐ ์์ผ๋ฏ๋ก ๋์ผํ ์ ์ฅ์ ์ธ์คํด์ค๋ฅผ ๋ฐํํ์ฌ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ ์ฝํ๊ณ ์๋ชป๋ ๊ธ์ ์ฐจ์ด๋ฅผ ๋ฐฉ์งํฉ๋๋ค. ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋๋ผ๋ Redux๋ ํต์ฌ ๊ฒ์ฆ์๋ฅผ ์ํ์ง ์๋ ๊ฒ์ฒ๋ผ ๋ณด์ด๋ฉฐ Immer๋ ๊ฐ์ธ์ ์ผ๋ก ์ด์ ๋ํ ๊ด์ฐฎ์ ๋ณดํธ ์ฅ์น๋ผ๊ณ ์๊ฐํฉ๋๋ค. ๋๋ ๊ทธ๊ฒ์ด Redux๋ฅผ ๋ฐฐ์ฐ๋ ๋ชฉ์ ์ ์ด๋ ์ ๋ ๋ฌด๋๋จ๋ฆฌ๋ ๊ฒ์ ๋์ํ์ง๋ง ์์ํ FP๋ฅผ ๋ฐฐ์ฐ๊ณ ์ถ์ง ์๊ฑฐ๋ ์ธ์ํ์ง ๋ชปํ๋ Redux๋ฅผ ๋ฐฐ์ฐ๋ ๋ง์ ๊ฐ๋ฐ์๋ฅผ ๋ด ๋๋ค.
๋ฒค์น๋งํนํ๋ฉด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋์จํ๊ฒ ํ๊ธฐ ์ํด ๋ณต์ก์ฑ์ ์ถ๊ฐํ๋ ๊ฒ ์ธ์๋ ์๋ฌด๊ฒ๋ ํ์ง ์์ ๊ฒ์ ๋๋ค.
๋ด๊ฐ ์๋ ํ, Immer๊ฐ Proxy๋ฅผ ๊ตฌํํ๋ ๋ฐฉ์์ ์ค์ ๋ก ๋ณ๊ฒฝ๋ ๊ฒฝ์ฐ์๋ง ์ฑ๋ฅ ์ค๋ฒํค๋๊ฐ ์์ผ๋ฏ๋ก ์ผ๋ฐ์ ์ธ ๋ณ๊ฒฝ ๋ถ๊ฐ๋ฅํ ์ ๋ฐ์ดํธ ๋ฆฌ๋์์๋ ์ฑ๋ฅ ์ค๋ฒํค๋๊ฐ ์์ด์ผ ํฉ๋๋ค. ์ด ์ ๋๋ฉด ๊ด์ฐฎ์ ๋ฐธ๋ฐ์ค๋ผ๊ณ ์๊ฐํฉ๋๋ค.
๋ก๊ฑฐ, devTools ๋ฐ Thunk๋ Starter์ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์ถ๊ฐ๋์ด์ผ ํ๋ฉฐ ๋๋จธ์ง๋ ๊ฐ์ธ์ ์ธ ์ ํ์ ๋ ๊ฐ๊น์ต๋๋ค.
์ ๊ฑฐ๋ฅผ ๊ณ ๋ คํ๊ณ ์ถ์ ๋ช ๊ฐ์ง ๋ค๋ฅธ ์ฌํญ์ด ์์ต๋๋ค(๊ฐ์ธ์ ์ผ๋ก ์ฑ๋ฅ ์ค๋ฒํค๋๋ฅผ ๋ณด์ํ๋ ๊ฐ๋ฐ์ ๋๊ตฌ์ ๋นํด ๋ก๊ฑฐ์ ํฐ ์ด์ ์ ๋ณด์ง๋ ๋ชปํจ), https://github.com/markerikson/ ์ฐธ์กฐ redux-starter-kit/issues/19. ๊ทธ๋ฌ๋ Immer ๋ฐ Thunk์ ํ์ฌ ์ฌ์ฉ๊ณผ ๊ฐ์ด ๋ค์ ํธํ๋๋ ๊ฒฝ์ฐ ๋ ๋ง์ ๊ฒ์ ์ถ๊ฐํ๋ ๊ฒ์ ๋ฐ๋ํ์ง ์์ต๋๋ค.
๋์์ ๋ฐ๋ผ ์ํ๋ฅผ ๋ณ๊ฒฝํ์ง ์์ผ๋ ค๋ ๊ฒฝ์ฐ๊ฐ ์์ผ๋ฏ๋ก ๋์ผํ ์ ์ฅ์ ์ธ์คํด์ค๋ฅผ ๋ฐํํ์ฌ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ ์ฝํ๊ณ ์๋ชป๋ ๊ธ์ ์ฐจ์ด๋ฅผ ๋ฐฉ์งํฉ๋๋ค. ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋๋ผ๋ Redux๋ ํต์ฌ ๊ฒ์ฆ์๋ฅผ ์ํ์ง ์๋ ๊ฒ์ฒ๋ผ ๋ณด์ด๋ฉฐ Immer๋ ๊ฐ์ธ์ ์ผ๋ก ์ด์ ๋ํ ๊ด์ฐฎ์ ๋ณดํธ ์ฅ์น๋ผ๊ณ ์๊ฐํฉ๋๋ค. ๋๋ ๊ทธ๊ฒ์ด Redux๋ฅผ ๋ฐฐ์ฐ๋ ๋ชฉ์ ์ ์ด๋ ์ ๋ ๋ฌด๋๋จ๋ฆฌ๋ ๊ฒ์ ๋์ํ์ง๋ง ์์ํ FP๋ฅผ ๋ฐฐ์ฐ๊ณ ์ถ์ง ์๊ฑฐ๋ ์ธ์ํ์ง ๋ชปํ๋ Redux๋ฅผ ๋ฐฐ์ฐ๋ ๋ง์ ๊ฐ๋ฐ์๋ฅผ ๋ด ๋๋ค.
@nickmccurdy ๋๋ ๋น์ ์ ๊ด์ ์ ์์ ํ ์ดํดํ๊ณ FP, ๋์ฐ๋ณ์ด ๋ฑ์ ์ผ๋ถ ๊ฐ๋ ์ผ๋ก ์ธํด ํ์ต ์ฅ์ ๊ฐ ์์ด์ผํ๋ค๋ ๋ฐ ๋์ํฉ๋๋ค. ๊ทธ๋ฌ๋ ๊ต์ก์๋ก์ ๋๋ ๊ฒฌ์ต์์๊ฒ ๊ทธ๋ค๋ก๋ถํฐ ๋ณต์ก์ฑ์ ์จ๊น๋๋ค. ์ด์จ๋ , ๊ทธ๊ฒ์ ๋จ์ง ์ทจํฅ์ ๋ฌธ์ ์ ๋๋ค. ์ ๋ ํ์ต๊ณผ ์ง๋ณด๋ฅผ ์ถ๊ตฌํ๋ ํ๋ก์ ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ด ์ ์์ ๋ณด๊ณ ์๋ ๋ด ๋ณธ๋ฅ์ ์ด๋ป๊ฒ๋ ์ฐ๋ฆฌ๊ฐ ์์ฉ์ ํตํด ์์ผ๋ก ๋์๊ฐ์ง๋ง ํ์ค์ ๋ฐ๋ผ ํด๋ณดํ ๊ฒ์ด๋ผ๊ณ ๋งํฉ๋๋ค. ์ฐธ๊ณ ๋ก ์ง๊ธ Redux ํ์ค์ ๊ฐ๋ฅด์น๋ ์น์ ๋ชจ๋ ์ฝํ ์ธ ์ ๊ทธ๊ฒ์ด ๋ง์นจ๋ด ์ด๋ป๊ฒ ์ฑํ๋๊ณ ์๋์ง ์๊ฐํด ๋ณด์ญ์์ค.
๋ด๊ฐ ์๋ ํ, Immer๊ฐ Proxy๋ฅผ ๊ตฌํํ๋ ๋ฐฉ์์ ์ค์ ๋ก ๋ณ๊ฒฝ๋ ๊ฒฝ์ฐ์๋ง ์ฑ๋ฅ ์ค๋ฒํค๋๊ฐ ์์ผ๋ฏ๋ก ์ผ๋ฐ์ ์ธ ๋ณ๊ฒฝ ๋ถ๊ฐ๋ฅํ ์ ๋ฐ์ดํธ ๋ฆฌ๋์์๋ ์ฑ๋ฅ ์ค๋ฒํค๋๊ฐ ์์ด์ผ ํฉ๋๋ค. ์ด ์ ๋๋ฉด ๊ด์ฐฎ์ ๋ฐธ๋ฐ์ค๋ผ๊ณ ์๊ฐํฉ๋๋ค.
๋ณต์ก์ฑ ๊ณ์ธต์ ์ถ๊ฐํ๋ค๋ ๊ฒ์ Immer
๊ฐ ํ ๋ฒ๋ ์์๊ณ ์ด์ ๊ทธ๋ด ์ ์๋ค๋ ๋ป์
๋๋ค. ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ์ด๋ฅผ ์ง์ํ๊ณ , ํ
์คํธํ๊ณ , ์ฑ๋ฅ ๋ฌธ์ ๋ฅผ ํ๊ฐํ๊ณ , ๋ง์ง๋ง์ผ๋ก ์ค์ํ ๊ฒ์ ์ฌ๊ธฐ ์ด ์น์
์ ์ ๋ฅผ ๋๋ ต๊ฒ ๋ง๋ญ๋๋ค.
Immer.js - ์๋ ๋๊ฒฐ
Immer๋ ๋์ฐ๋ฌผ์ ์ฌ์ฉํ์ฌ ์์ ๋ ๋ชจ๋ ์ํ ํธ๋ฆฌ๋ฅผ ์๋์ผ๋ก ๋๊ฒฐํฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ์์ฐ์ ์ธ๋ถ์์ ์ํ ํธ๋ฆฌ๊ฐ ์ฐ๋ฐ์ ์ผ๋ก ์์ ๋๋ ๊ฒ์ ๋ฐฉ์งํ ์ ์์ต๋๋ค. ์ด๊ฒ์ ์ฑ๋ฅ์ ์ํฅ์ ๋ฏธ์น๋ฏ๋ก ํ๋ก๋์ ์์๋ ์ด ์ต์ ์ ๋นํ์ฑํํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก ํ์ฑํ๋์ด ์์ต๋๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก ๋ก์ปฌ ๊ฐ๋ฐ ์ค์๋ ์ผ์ ธ ์๊ณ ํ๋ก๋์ ์์๋ ๊บผ์ ธ ์์ต๋๋ค. ์ด ๊ธฐ๋ฅ์ ๋ช ์์ ์ผ๋ก ์ผ๊ฑฐ๋ ๋๋ ค๋ฉด setAutoFreeze(true / false)๋ฅผ ์ฌ์ฉํ์ญ์์ค.
๊ทธ๋ฆฌ๊ณ ๊ฐ์๊ธฐ Development / Prod
์ถ๊ฐ๋ ๊ธฐ๋ฅ๋ ์ง์ํด์ผ ํฉ๋๋ค. ๊ทธ๊ฒ์ ๋จ์ง ์ข์ ์์ ์์
์ด๊ณ ๋ง์ ๊ฒ์ ๊ตํํ์ง ์๋ ๊ฒ์ ๋ํ ๊ฑฑ์ ์
๋๋ค. ๊ทธ๋ฌ๋ ๋ค์ ๋งํ์ง๋ง ์ด๊ฒ์ ๋จ์ง ์ ๊ฐ์ธ์ ์ธ ์๊ฒฌ์ผ ๋ฟ์
๋๋ค.
@codedavinci : ์ด redux-starter-kit
๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์์ ์ "๊ธฐ๋ณธ" Redux ์ ์ฅ์ ์ค์ ํ๋ก์ธ์ค ์์ ์ ์ฉํ ๋๊ตฌ์ ์ถ์ํ๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์
๋๋ค. ๋ํ ์ด๊ฒ์ Redux ์ฝ์ด ์์ฒด๋ก ๋ค์ด๊ฐ๋ ๊ฒ์ด _์๋๋๋ค_. ์คํ๋ ค ์ฐ๋ฆฌ๊ฐ ๊ฒฐ๊ตญ Redux ์กฐ์ง์ "๊ณต์์ ์ธ" ์ผ๋ถ๋ฅผ ๋ง๋ค๊ณ ์ ํ๋ ๋ณ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ๋ค์ด๊ฐ๋ ๊ฒ์
๋๋ค.
๊ธฐ์กด์ ๋ชจ๋ Redux ์ฝ๋๊ฐ ์๋ํฉ๋๋ค. ๊ธฐ์กด์ ๋ชจ๋ ํํ ๋ฆฌ์ผ์ ์ฌ์ ํ โโ๊ด์ฐฎ์ต๋๋ค. Redux๋ฅผ ์ค์ ํ๊ณ ์ฌ์ฉํ๊ธฐ ์ํด ๊ณต์์ ์ผ๋ก ์ง์๋๋ ๋ ๊ฐ๋จํ ์ ๊ทผ ๋ฐฉ์์ ์ถ๊ฐํ๋ ค๊ณ ํฉ๋๋ค.
@markerikson ๋๋ ์คํํฐ ํคํธ๋ฅผ ๊ฐ๋ ๋ชฉํ๋ฅผ ์ดํดํ๊ณ ์์์ ์ธ๊ธํ ๋ชจ๋ ๊ฒ์ ๋ํด ์์ ํ ์ค๋งํ์ต๋๋ค. Immer.js
์ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๊ฐ๋
์ ๋ฐ๊พธ๋ ๊ฒ์ ์ฝ๊ฐ ์ ํญํฉ๋๋ค. ์ฌ๋๋ค์ ๊ฒฐ๊ตญ ๋ฐฐ์ธ ๊ฒ์
๋๋ค starter-kit
ํจํด์ ์ฌ์ฉํ๊ณ ํต์ฌ ๊ฐ๋
์ ์์ ํ ๋ฌด์ํฉ๋๋ค. ์์ ๋์ฐ๋ณ์ด๊ฐ ์๋ค๋ ๊ฒ์ด ๋ชจํ ์
๋๋ค. Redux๋ ํญ์ ๊ทธ๊ฒ์ ํ๋งคํ๊ณ ์์ผ๋ฉฐ, ์ด๋ ๋ธ๋๋์ ์ผ๋ถ์
๋๋ค.
์ถ์ : Immer.js
๊ฐ ์๋ฌด ๊ฒ๋ ๋ณ๊ฒฝํ์ง ์๋๋ค๋ ๊ฒ์ ์ถฉ๋ถํ ์ดํดํฉ๋๋ค. ์คํ๋ ค ๋ณ๊ฒฝํ์ง ์๋๋ก ๋์์ค๋๋ค. ์ ๋ push
, splice
์ ๊ฐ์ด ํ์ฉ๋๋ ๊ตฌ๋ฌธ ํ์ค์ ๋ํด์๋ง ์ด์ผ๊ธฐํ๊ณ ์์ต๋๋ค. ...
์๋ง๋, ๊ทธ๊ฒ์ ๋ ์์ ์ด ๋ณํ์ ์ ํญํ๋ ๊ฒ๋ฟ์ ๋๋ค :)
@codedavinci : ์, ์ฐ๋ ค์ ์์ ์ ์ดํดํฉ๋๋ค. ๊ทธ๋๋ Redux์ ๋ํ ์ผ๋ฐ์ ์ธ ๋ถ๋ง ์ค ํ๋๋ ์ ์ ํ ๋ณ๊ฒฝ ๋ถ๊ฐ๋ฅํ ์ ๋ฐ์ดํธ ์ฝ๋๋ฅผ ์์ฑํด์ผ ํ๋ ๊ณ ํต์ด๋ฉฐ Immer๋ ์ด๋ฌํ ์ ๋ฐ์ดํธ๋ฅผ ๋จ์ํํ๋ ๋ฐ ์์ด ๋ด๊ฐ ๋ณธ ์ต๊ณ ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค.
@markerikson , ์ค์ ๋ก immer
ํ๊ณ ๋ค์๊ณ ๋งค์ฐ ๊ฐ๋ณ๊ณ ๊ฐ๋จํ๋ฉฐ ํจ์จ์ ์ด๋ผ๋ ๊ฒ์ ์์์ต๋๋ค. ์ค์ ๋ก ํ๋ ธ์ต๋๋ค :) .
์ด๋ค ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ์์ฑํ๊ณ ์์ต๋๊น? ์ ๊ฒ๋ค:
https://github.com/markerikson/redux-starter-kit
https://www.npmjs.com/package/@acemarke/redux -starter-kit
https://unpkg.com/@acemarke/redux [email protected]/
๋ค, ๋ฐ๋ก ๊ทธ๊ฒ์ ๋๋ค.
@nickmccurdy ์๋ ๋๋ถ๋ถ ํด๋ง๊ณผ ๊ด๋ จํ์ฌ ๋ ผ์ ๋ฐ ํฉ๋ณ์ ๊ธฐ๋ค๋ฆฌ๋ ๋ง์ PR์ด ์์ง๋ง ํ๋ก์ ํธ๋ฅผ ์ฅ๊ธฐ์ ์ผ๋ก ์ง์คํ๋ ๋ฐฉ๋ฒ์ ๋ํ ๋ ผ์๋ ์์ต๋๋ค. ๋๋ ๊ทธ๊ฒ๋ค์ ์ดํด๋ณด๊ธฐ ์ํด ๋์๋ค๋ ์ผ ํ์ง๋ง ์ง๋ ๋ช ์ฃผ ๋์ ๋ค๋ฅธ ์ผ๋ค๋ก ๋ฐ๋นด๋ค(๋ด์ผ ๋ด๊ฐ ํ ์ปจํผ๋ฐ์ค ๊ฐ์ฐ์ ํฌํจํ์ฌ).
@nickmccurdy & @markerikson์ ํฐ ๋ฐ์ ๐ ๋๋ ๊ทธ๊ฒ์ ๋จ์ํจ๊ณผ ํจ์จ์ฑ์ ์ข์ํฉ๋๋ค. @nickmccurdy ๋ ๋น์ ์ด ํ๋ก์ ํธ์ ๋งค์ฐ ์ ๊ทน์ ๊ทธ๊ฒ์ ์ํ๋์ง ์๋ ค์ฃผ์ธ์! :)
๋ฌผ๋ก ๊ฐ์ฌํฉ๋๋ค. ์ ๋ฌธ์ ์์ ๊ณต๊ฐ ํ ๋ก ์ ์์ํ๋ ๊ฒ์ด ๊ฐ์ฅ ์ข์ง๋ง [email protected] ๋๋ Discord๋ฅผ ํตํด ์ ์๊ฒ ์ง์ ์ฐ๋ฝํ ์ ์์ต๋๋ค.
combineReducers
๋ถํ ์ ๋ํ +1 . ๋๋ ๊ทธ๊ฒ์ ๊ฐ์ฅ ์ค๋ซ๋์ ์ฌ์ฉํ๊ณ , ๋ง์ฝ ๊ทธ๋ ๋ค๋ฉด ๋ด ๊ฐ๊ฒ๊ฐ ์ด๋ป๊ฒ ์ด์๋๋์ง์ ๋ํด ๊น์ด ์๊ฐํ์ง ์์๊ธฐ ๋๋ฌธ์
๋๋ค.
ํ์ฌ ๋ค์ ๋ผ์ธ์ ๋ฐ๋ผ ๊ฐ์๊ธฐ ๊ธฐ๋ฅ์ ์ค์ ํ๊ณ ์ถ์ต๋๋ค.
function reducer(prevState, event, handledNavigation = false) {
if (event.type === 'NAVIGATION' && !handledNavigation) {
return reducer(onNavigate(prevState, event), event, true);
}
const pageReducer = pageReducers[prevState.activePage];
const nextSessionState = sessionReducer(prevState.sessionState, event);
const nextPageState = pageReducer(prevState.pageState, nextSessionState, event);
return {
activePage: prevState.activePage,
pageState: nextPageState,
sessionState: nextSessionState,
};
}
CombineReducers๊ฐ ์ค์ ๋ก ํ์ฉํ์ง ์๋ ๊ฒ์ ๋๋ค.
@abradley2 : ๊ทธ๊ฒ์ด ๋น์ ์ด ์๊ตฌํ๋ ๊ฒ์ด๋ผ๋ฉด Redux ์ฝ์ด์์ combineReducers
๋ฅผ ์ ๊ฑฐํ ๊ณํ์ด ์์ต๋๋ค. ๊ทธ๋ฌ๋ ์, ์ฐ๋ฆฌ๋ ํญ์ combineReducers
๊ฐ ๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ์ฌ์ฉ ์ฌ๋ก์ ์ ํธ๋ฆฌํฐ์ด๋ฉฐ ์์ ์ ์ํฉ์ ๋ง๋ ์ฌ์ฉ์ ์ ์ ๊ฐ์๊ธฐ ๋
ผ๋ฆฌ๋ฅผ ์์ฑํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
redux-starter-kit
ํจํค์ง ์ด๋ฆ์ด ์๊ณ ์ ์ฅ์๊ฐ https://github.com/reduxjs/redux-starter-kit ์ ์กฐ์ง์ผ๋ก ์ด๋๋์์ต๋๋ค. ์ด ์ค๋ ๋๋ฅผ ๋ซ์ต๋๋ค. ํด๋น ๋ฆฌํฌ์งํ ๋ฆฌ์์ ์ถ๊ฐ ํ ๋ก ์ด ๋ฐ์ํ ์ ์์ต๋๋ค.
๋ํ ๊ธฐ๋ณธ์ ์ผ๋ก ๋์ฐ๋ณ์ด ๋ฐ ์ง๋ ฌํ ๊ฒ์ฌ๋ฅผ ์ถ๊ฐํ๋ ์์ ์ ์์ํ๊ณ ์์ต๋๋ค.
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
๊ทธ๋์, ์ด... ๋ด๊ฐ ๊ฐ์ ํ ๊ฐ์ง:
์ด์ ์ค๋ํซ๊ณผ ๋ค๋ฅธ ์ :
enhancers
๊ตฌ์ฑ ์ต์ ์ ๋ฃ์์ต๋๋ค.selectorator
์์กด์ฑ์ ๋ด ๋ณด๋ธcreateSelector
์๊ฐ?