Redux vs Recoil

Table of Contents

๐Ÿคท TL;DR

  • Redux๋Š” ์•ˆ์ •์ ์ด์ง€๋งŒ, ์„ ์–ธ๊ณผ ์‚ฌ์šฉ์ด ๋ณต์žกํ•˜๋‹ค.
  • Recoil์€ ์‚ฌ์šฉ์ด ๋งค์šฐ ์‰ฝ์ง€๋งŒ ์ •์‹ ๋ฒ„์ „์ด ์—†๋‹ค.
  • ํ”„๋กœ์ ํŠธ ๊ทœ๋ชจ์— ๋”ฐ๋ผ ๋งˆ์Œ์— ๋“œ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ ํƒํ•˜์ž

๐Ÿšช ์„œ๋ก 

์šฐ๋ฆฌ๋Š” React๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๋ณดํ†ต useState๋ฅผ ํ†ตํ•ด ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. useState๋Š” ์ •๋ง ์„น์‹œํ•˜์ง€๋งŒ, ํ•œ ๊ฐ€์ง€ ๋„ˆ๋ฌด ํฐ ๋‹จ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ”๋กœ ์ปดํฌ๋„ŒํŠธ๋ผ๋ฆฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›๋Š” ๋ฐ ์‚ฌ์šฉํ•˜๊ธฐ๊ฐ€ ํž˜๋“ค๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. ๊ทธ ์ผ์„ ํ•˜๊ธฐ ์œ„ํ•ด ๋“ฑ์žฅํ•œ ๊ฒƒ์ด ๋ฐ”๋กœ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค. ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ํ•„์š”์„ฑ์— ๋Œ€ํ•ด ๊ณต๊ฐํ•˜์ง€ ๋ชปํ•˜๋Š” ๋ถ„๋“ค์„ ์œ„ํ•ด ์งง์€ ํ† ๋ง‰๊ธ€์„ ๋งˆ๋ จํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

โœ… ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์™œ ์‚ฌ์šฉํ•˜๋‚˜์š”?

์œ ์ €๊ฐ€ ๋กœ๊ทธ์ธํ•ด ์žˆ๋Š” ์ •๋ณด๋ฅผ ๋‹ด์€ state๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋ฉด Root ์ปดํฌ๋„ŒํŠธ๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

export default function App() {
  const [userInfo, setUserInfo] = useState("not logged in");
  return (
    <React.StrictMode>
      <Router>
        <Routes>
          <Route path="/login" element={<Login setUserInfo={setUserInfo} />} />
        </Routes>
      </Router>
    </React.StrictMode>
  );
}

์—ฌ๊ธฐ๊นŒ์ง„ ๊ทธ๋ ‡๊ฒŒ ์–ด๋ ต์ง€ ์•Š๋„ค์š”. ๋‹จ์ˆœํžˆ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€์— setState ํ•จ์ˆ˜๋ฅผ ๋นŒ๋ ค์ค˜์„œ userInfo๋ฅผ ๊ฐฑ์‹ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋ฉด ๋˜๋‹ˆ๊นŒ์š”.

ํ•˜์ง€๋งŒ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๊ฐ€ ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ถ„๋ฆฌ๋œ๋‹ค๋ฉด ์–ด๋–จ๊นŒ์š”? ์ด๋ฅผํ…Œ๋ฉด, ๋กœ๊ทธ์ธ ํ™”๋ฉด์—์„œ ๋‚ด ์„œ๋น„์Šค์— ๋Œ€ํ•œ ๊ด‘๊ณ  ์นดํ”ผ์™€ ์งง์€ ์˜์ƒ๊ฐ™์€ ๋ฏธ๋””์–ด๋ฅผ ์ฒจ๋ถ€ํ•œ ์•„์ฃผ ์ด์œ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋ฅผ ๋งŒ๋“ค๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿผ ๊ด€์‹ฌ์‚ฌ ๋ถ„๋ฆฌ๋ฅผ ์œ„ํ•ด ์‹ค์ œ ๋กœ๊ทธ์ธ์˜ ๊ธฐ๋Šฅ์„ ํ•˜๋Š” ๋ถ€๋ถ„์„ ๋ณ„๋„์˜ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ถ„๋ฆฌํ•ด์•ผ ํ•  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

export default function Login({
  setUserInfo,
}: {
  setUserInfo: React.Dispatch<React.SetStateAction<string>>,
}) {
  return (
    <div>
      <div>์šฐ๋ฆฌ ์„œ๋น„์Šค ๋ฆฌ์–ผ๊ตฟ ๋‹น์žฅ๋ฐ”๋กœ์ง€๊ธˆ ๋กœ๊ทธ์ธ ๋ผ์–ํ˜ธ์šฐ~!~!</div>
      <LoginForm setUserInfo={setUserInfo} />
    </div>
  );
}

๋ฐ›์€ setUserInfo๋ฅผ LoginForm ์ปดํฌ๋„ŒํŠธ์— ํ•œ๋ฒˆ ๋” ๋‚ด๋ ค์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค. ์Œ.. ์•„์ง๊นŒ์ง€๋Š” ์ฐธ์„ ๋งŒ ํ•˜๋„ค์š”. ํ•˜์ง€๋งŒ ๋” ํฐ ๋ฌธ์ œ๊ฐ€ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ๋กœ๊ทธ์ธํ•œ ์ •๋ณด๋ฅผ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”? ๋ชจ๋“  ๋ผ์šฐํ„ฐ์— ๋Œ€ํ•ด ๋ฃจํŠธ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๊ฐ€์ง„ userInfo๋ฅผ ์ „๋‹ฌํ•ด ์ฃผ๊ฒ ์Šต๋‹ˆ๋‹ค.

export default function App() {
  const [userInfo, setUserInfo] = useState("not logged in");
  return (
    <React.StrictMode>
      <Router>
        <Routes>
          <Route path="/login" element={<Login setUserInfo={setUserInfo} />} />
          <Route path="/service1" element={<Service1 userInfo={userInfo} />} />
          <Route path="/service2" element={<Service2 userInfo={userInfo} />} />
          <Route path="/service3" element={<Service3 userInfo={userInfo} />} />
          <Route path="/service4" element={<Service4 userInfo={userInfo} />} />
          <Route path="/service5" element={<Service5 userInfo={userInfo} />} />
          <Route path="/service6" element={<Service6 userInfo={userInfo} />} />
          <Route path="/service7" element={<Service7 userInfo={userInfo} />} />
          <Route path="/service8" element={<Service8 userInfo={userInfo} />} />
        </Routes>
      </Router>
    </React.StrictMode>
  );
}

๋ผ์šฐํ„ฐ๋‹ˆ๊นŒ ์ด์ •๋„ ๋”๋Ÿฌ์›€์€ ๊ดœ์ฐฎ์„ ๊ฒƒ ๊ฐ™๋‹ค๊ตฌ์š”? ๊ทธ๋ ‡๋‹ค๋ฉด ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ์—์„œ ํ•„์š”๋กœ ํ•˜๋Š” ์ •๋ณด๊ฐ€ ๋กœ๊ทธ์ธ ์ •๋ณด๋งŒ์ด ์•„๋‹ˆ๋ผ๋ฉด์š”? newInfo๋ฅผ ๋ถˆํŠน์ • ๋‹ค์ˆ˜์˜ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ฐธ์กฐํ•œ๋‹ค๋ฉด์š”?

export default function App() {
  const [userInfo, setUserInfo] = useState("not logged in");
  const [newInfo, setNewInfo] = useState(0);
  return (
    <React.StrictMode>
      <Router>
        <Routes>
          <Route path="/login" element={<Login setUserInfo={setUserInfo} />} />
          <Route path="/service1" element={<Service1 userInfo={userInfo} />} />
          <Route
            path="/service2"
            element={<Service2 userInfo={userInfo} newInfo={newInfo} />}
          />
          <Route path="/service3" element={<Service3 userInfo={userInfo} />} />
          <Route path="/service4" element={<Service4 userInfo={userInfo} />} />
          <Route
            path="/service5"
            element={<Service5 userInfo={userInfo} newInfo={newInfo} />}
          />
          <Route path="/service6" element={<Service6 userInfo={userInfo} />} />
          <Route
            path="/service7"
            element={<Service7 userInfo={userInfo} newInfo={newInfo} />}
          />
          <Route path="/service8" element={<Service8 userInfo={userInfo} />} />
        </Routes>
      </Router>
    </React.StrictMode>
  );
}

์•„์ง๋„ ๋ฒ„ํ‹ธ ๋งŒ ํ•˜์‹ ๊ฐ€์š”? ๊ทธ๋Ÿผ ๋งˆ์ง€๋ง‰์œผ๋กœ **Service3์˜ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์ธ ChildComponent1์—์„œ ๋ณ€๊ฒฝํ•œ ๋ฐ์ดํ„ฐ ๊ฐ’์„ Service1์˜ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์ธ ChildComponent2๋กœ ์ „๋‹ฌํ•ด ์ฃผ๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ์š”?**

๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ ํŒ€์€ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์–ด๋–ค ๊ฒƒ์„ ์‚ฌ์šฉํ• ์ง€ ๊ณ ๋ฏผํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹น์žฅ ํšŒ์˜์—์„œ ๊ฑฐ๋ก ๋˜์—ˆ๋˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” Redux, Recoil, Context API, Mobx ์ •๋„๊ฐ€ ์žˆ๋Š”๋ฐ์š”, ์˜ค๋Š˜์€ ๊ทธ ์ค‘์— Redux์™€ Recoil์— ๋Œ€ํ•ด ๊ฐ€๋ณ๊ฒŒ ์•Œ์•„๋ณด๊ณ  ๋น„๊ตํ•ด ๋ณด๋Š” ์‹œ๊ฐ„์„ ๊ฐ€์กŒ์Šต๋‹ˆ๋‹ค. ์ด ๊ธ€์—์„œ๋Š” ์ž‘๋™ ์›๋ฆฌ๋ณด๋‹ค๋Š” ์‚ฌ์šฉ์ƒ์˜ ์žฅ๋‹จ์ ์„ ์ค‘์‹ฌ์œผ๋กœ ์ •๋ฆฌํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๐Ÿฌ Redux

Redux์— ๋Œ€ํ•ด.araboja

Untitled

Redux๋Š” ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ค‘์—์„œ๋„ ๊ฐ€์žฅ ๋Œ€์ค‘์ ์ธ ์นœ๊ตฌ์ž…๋‹ˆ๋‹ค. ์•„๋งˆ recoil์ฒ˜๋Ÿผ ๋ฆฌ์•กํŠธ์— ์ข…์†์ ์ด์ง€๋„ ์•Š๊ณ , mobx๋ณด๋‹ค ์˜ค๋ž˜๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์ด ์•„๋‹๊นŒ์š”? ์•„๋ฌดํŠผ npm trends์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์••๋„์ ์ธ ์ปค๋ฎค๋‹ˆํ‹ฐ ํฌ๊ธฐ๋ฅผ ์ž๋ž‘ํ•ฉ๋‹ˆ๋‹ค. ๋ ˆํผ๋Ÿฐ์Šค๊ฐ€ ๋ฌด์ฒ™ ๋งŽ๊ณ , ์Œ.. ๋ ˆํผ๋Ÿฐ์Šค๊ฐ€ ๋ฌด์ฒ™ ๋งŽ์Šต๋‹ˆ๋‹ค. ํ•œ๊ธ€๋กœ ๊ฒ€์ƒ‰ํ•ด๋„ ๋‹น์žฅ ์ด ๊ธ€์„ ์“ธ ์ด์œ ๊ฐ€ ์žˆ๋‚˜ ์‹ถ์„ ์ •๋„๋กœ ์ง€๋‚˜์น˜๊ฒŒ ๋งŽ์€ ์ •๋ฆฌ๊ธ€์ด ๋‚˜์˜ค๋„ค์š”.

Untitled

Redux๋Š” Flux ์•„ํ‚คํ…์ณ๋ฅผ ๊ฐœ์„ ํ•œ ๊ตฌ์กฐ๋กœ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. 1) ์ฝ๊ธฐ ์ „์šฉ์ธ ์ƒํƒœ๋ฅผ 2) ํ•˜๋‚˜์˜ store๊ฐ€ 3) ์ˆœ์ˆ˜ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ๊ฐฑ์‹ ํ•œ๋‹ค๋Š” ์„ธ ๊ฐ€์ง€ ๋ฉ”์ธ ์ปจ์…‰์ด ์žˆ๋‹ค๊ณ  ํ•˜๋„ค์š”. ๋” ์ž์„ธํ•œ ์„ค๋ช…์€ ์œ„ ์‚ฌ์ง„์˜ ์ถœ์ฒ˜ ๋งํฌ์— ์ž˜ ์„ค๋ช…์ด ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

์‚ฌ์šฉํ•ด ๋ด…์‹œ๋‹ค

npm i redux react-redux @reduxjs/toolkit

์šฐ์„  ์„ธ ๊ฐ€์ง€ ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. @reduxjs/toolkit ์ด๋ผ๋Š” ํŒจํ‚ค์ง€๋Š” redux๋ฅผ ์กฐ๊ธˆ ๋” ํŽธํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ฃผ๋Š” ๋„๊ตฌ์ธ๋ฐ์š”, ๊ฐœ์ธ์ ์œผ๋กœ RTK ์—†์ด ๋ฆฌ๋•์Šค๋ฅผ ์ฒ˜์Œ ์‹œ์ž‘ํ•˜๊ธฐ๊ฐ€ ๊ต‰์žฅํžˆ ์–ด๋ ค์› ๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉํ•˜๋Š” ์ชฝ์œผ๋กœ ๊ธธ์„ ํ‹€์—ˆ์Šต๋‹ˆ๋‹ค.

// count.ts
import { createSlice, PayloadAction } from "@reduxjs/toolkit";

export interface CounterState {
  // State์˜ interface ์„ ์–ธ
  value: number;
  amount: number;
}

const initialState: CounterState = {
  // ์ดˆ๊ธฐ๊ฐ’ ์„ ์–ธ
  value: 0,
  amount: 1,
};

export const counterSlice = createSlice({
  name: "counter",
  initialState,
  reducers: {
    increase: (state) => {
      state.value += state.amount;
    },
    decrease: (state) => {
      state.value -= state.amount;
    },
    init: (state, action: PayloadAction<number>) => {
      // value๊ฐ’์„ ์ง์ ‘ ์„ค์ •ํ•˜๋Š” action
      state.value = action.payload;
    },
  },
});

export const { increase, decrease, init } = counterSlice.actions;

export default counterSlice.reducer;

์ „์—ญ ์ƒํƒœ๋งˆ๋‹ค ์œ„์™€ ๊ฐ™์ด reducer๋ฅผ ์„ ์–ธํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ์—๋Š” init action์ฒ˜๋Ÿผ setState์˜ ์—ญํ• ์„ ํ•˜๋Š” ๋…€์„๋งŒ ์„ ์–ธํ•ด ์ฃผ๋ฉด ๋ฌธ์ œ ์—†์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์œผ๋กœ ๋ณด์ด๋„ค์š”. ๊ทธ๋Ÿผ์—๋„ ์—ฌ๋Ÿฌ ๊ฐœ์˜ action์„ ์„ ์–ธํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๋ถ€๋ถ„์€ ๋งค๋ ฅ์ ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์ „์—ญ ์ƒํƒœ๊ฐ€ Object์ฒ˜๋Ÿผ ๋ณต์žกํ•œ ํƒ€์ž…์œผ๋กœ ๋˜์–ด ์žˆ๋‹ค๋ฉด ๊ด€๋ฆฌํ•˜๋Š” ๋กœ์ง์„ action์— ์„ ์–ธํ•ด ๋‘๊ณ  ์žฌ์‚ฌ์šฉํ•˜๋ฉด ๋˜๋‹ˆ๊นŒ์š”.

๐Ÿ’ก ESLint airbnb rule๊ณผ์˜ ์ถฉ๋Œ

createSlice๋กœ ๋ฆฌ๋“€์„œ๋ฅผ ๋งŒ๋“ค๋‹ค ๋ณด๋ฉด ์•„๋ž˜ ์‚ฌ์ง„๊ณผ ๊ฐ™์ด ํŒจ๋Ÿฌ๋ฏธํ„ฐ๋กœ ๋“ค์–ด์˜จ state๊ฐ€ ๊ฐ€์ง„ ๊ฐ’์„ ์กฐ์ž‘ํ•ด์„  ์•ˆ๋œ๋‹ค๋Š” ๊ฒฝ๊ณ  ๋ฉ”์‹œ์ง€๋ฅผ ๋งˆ์ฃผ์น˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. airbnb ๋ฃฐ์— ํฌํ•จ๋˜์–ด ์žˆ๋Š” ๊ทœ์น™์ธ๋ฐ, redux-toolkit Issue #521์—์„œ ์ด์— ๋Œ€ํ•œ ์„ค๋ช…์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ ์‚ฌ๋žŒ๋“ค์€ airbnb ๋ฃฐ์„ ๊ทธ๋‹ฅ ์ข‹์•„ํ•˜์ง€ ์•Š๋Š”๊ตฐ์š”!

Untitled

ํ•ด๋‹น Rule์„ ๋น„ํ™œ์„ฑํ™” ํ•˜๋Š” ๊ฒƒ ์™ธ์— ์•ฝ๊ฐ„์˜ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ฃผ๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ๋Š”๋ฐ์š”, ์ด ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ•˜์‹œ๋ฉด ๋˜๊ฒ ์Šต๋‹ˆ๋‹ค.

// store.ts
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "./count";

export const store = configureStore({
  reducer: {
    counter: counterReducer,
  },
});

export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;

๋งŒ๋“  reducer๋“ค์„ ๊ด€๋ฆฌํ•˜๋Š” store๋ฅผ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค. ํ”ํžˆ ์•Œ๊ณ  ๊ณ„์‹œ๋Š” store์˜ ๊ฐœ๋…๊ณผ ๊ฐ™์œผ๋ฉฐ, ์ „์—ญ ์ƒํƒœ๊ฐ€ ๋” ํ•„์š”ํ•  ๋•Œ ๋งˆ๋‹ค ๋งŒ๋“  reducer๋“ค์„ configureStore ์•ˆ์— ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด ๋˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉํ•  ์ „์—ญ ์ƒํƒœ ์ˆ˜๋งŒํผ importํ•ด์„œ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ์ƒ๊ฐ์œผ๋กœ ์ž‘์„ฑํ•˜๋ฉด ๋  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

// App.tsx
import React, { useState } from "react";
import { Provider } from "react-redux";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import "./App.scss";
import Login from "./Login";
import { store } from "./redux/store";
import Test from "./Test";

export default function App() {
  return (
    <React.StrictMode>
      <Provider store={store}>
        <Router>
          <Routes>
            <Route path="/" element={<Test />} />
            <Route path="/login" element={<Login />} />
          </Routes>
        </Router>
      </Provider>
    </React.StrictMode>
  );
}

์ด์ œ ๋งŒ๋“  store๋ฅผ Provider๋ฅผ ํ†ตํ•ด ์—ฐ๊ฒฐํ•ด ์ค๋‹ˆ๋‹ค. Router์™€ ๋น„์Šทํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, Provider๋กœ ๋ฌถ์—ฌ ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ๋“ค์€ ๋ชจ๋‘ store์˜ ์ƒํƒœ๋“ค์„ ์ฐธ์กฐํ•˜๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” scope๋ฅผ ์ง€์ •ํ•˜๋Š” ๋Š๋‚Œ์œผ๋กœ ์ดํ•ดํ•˜๋ฉด ๋˜๊ฒ ๋„ค์š”.

// Test.tsx
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { decrease, increase, init } from './redux/count';
import { RootState } from './redux/store';

export default function Test() {
  const count = useSelector((state: RootState) => state.counter.value);
  const dispatch = useDispatch();
	return (
	...
	<button type="button"
	onClick={() => {
		dispatch(decrease());
	}}
	>-</button>
	...
	);
}

์‹ค์ œ ์‚ฌ์šฉ์€ ์œ„์™€ ๊ฐ™์ด ํ•ฉ๋‹ˆ๋‹ค. ์ฐธ์กฐํ•  ์ƒํƒœ๋Š” useSelector๋กœ, action์€ useDispatch๋ฅผ ์ด์šฉํ•ด ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. ๊ฐœ์ธ์ ์œผ๋กœ๋Š” action ๋ฉ”์†Œ๋“œ๋ฅผ importํ•ด์™”๋Š”๋ฐ ๊ทธ๊ฑธ ๋ฐ”๋กœ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•˜๊ณ  useDispatch๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๋Š” ์ ์ด ์กฐ๊ธˆ ์ด์ƒํ•˜๊ฒŒ ๋Š๊ปด์กŒ์Šต๋‹ˆ๋‹ค. ๋˜ ํƒ€์ž… ์˜ค๋ฅ˜๊ฐ€ ์žˆ์—ˆ๋Š”๋ฐ, ์ด๋ฅผ ์œ„ํ•ด RootState๋ผ๋Š” ๋ฐ˜ํ™˜ ํƒ€์ž…์„ ์„ ์–ธํ•ด์„œ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. store.ts ์ฝ”๋“œ์— ๋ณด์ด๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์•„๋ฌด๋ฐ๋‚˜ ์‚ฌ์šฉํ•ด๋„ ๋  ๋งŒํผ ์ถ”์ƒํ™”๊ฐ€ ๋˜์–ด์žˆ๋Š” ํƒ€์ž…์ธ๋ฐ ๊ธฐ๋ณธ์œผ๋กœ ์ง€์›ํ•ด์ฃผ์ง€ ์•Š๋Š” ๊ฒƒ์€ ์กฐ๊ธˆ ์•„์‰ฝ์Šต๋‹ˆ๋‹ค.

๋ฆฌ๋•์Šค.gif

์•„์ฃผ ๋ฌด์Œฉ๊ธด ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ†ตํ•ด ์ œ๋Œ€๋กœ ์ž‘๋™ํ•จ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ Redux ์“ฐ๋‚˜์š”?

์žฅ์ 

  • ๋ ˆํผ๋Ÿฐ์Šค๊ฐ€ ๋งค์šฐ ๋งŽ์Šต๋‹ˆ๋‹ค.
  • ๊ธ€์—๋Š” ์–ธ๊ธ‰ํ•˜์ง€ ์•Š์•˜์ง€๋งŒ Redux Devtools๋ฅผ ํ†ตํ•ด ๋””๋ฒ„๊น…์„ ์ง€์›ํ•ด ์ค€๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.
  • (Recoil๊ณผ ๋น„๊ตํ•ด์„œ) ์•ˆ์ •์ ์ด๊ณ , ๋ฏฟ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ €๋งŒ ์ž˜ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด์š”.

๋‹จ์ 

  • reducer, store, type ๋“ฑ๋“ฑ ์ƒํƒœ ํ•˜๋‚˜๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•œ ์ฝ”๋“œ๊ฐ€ ์ •๋ง ๊น๋‹ˆ๋‹ค.
  • ๋ ˆํผ๋Ÿฐ์Šค๊ฐ€ ๋„ˆ๋ฌด ๋งŽ์Šต๋‹ˆ๋‹ค.
  • ์œ„์˜ ๋‘ ๋ฌธ์ œ์ ์œผ๋กœ ์ธํ•ด ์ง„์ž…์žฅ๋ฒฝ์ด ๊ต‰์žฅํžˆ ๋†’์•˜์Šต๋‹ˆ๋‹ค.

Redux์— ๋Œ€ํ•œ ์ฒซ ์ธ์ƒ์€ ๊ต‰์žฅํžˆ ๋ถˆ์นœ์ ˆํ–ˆ์Šต๋‹ˆ๋‹ค. ์ปค๋ฎค๋‹ˆํ‹ฐ๊ฐ€ ํฐ ๊ฒƒ์€ ์ข‹์€๋ฐ, ์ง„์งœ ๋„ˆ๋ฌด ๋Œ€๋ฐ• ํฌ๋‹ค๋ณด๋‹ˆ ๋ ˆํผ๋Ÿฐ์Šค๋“ค์ด ์„œ๋กœ ๋ฐ˜๋Œ€ ๋ฐฉํ–ฅ์œผ๋กœ ์ €๋ฅผ ์ด๋„๋Š” ๊ฒฝ์šฐ๊ฐ€ ๊ฝค ๋งŽ์•˜์Šต๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ์ €๋„ ๋Œ€ํ•™๊ต ํ”„๋กœ์ ํŠธ๋ฅผ ํ•˜๋ฉด์„œ ์ด๋Ÿฐ ์  ๋•Œ๋ฌธ์— Redux๋ฅผ ํฌ๊ธฐํ•˜๊ณ  props๋ฅผ ๋งˆ๊ตฌ ๋‚ด๋ ธ๋‹ค ์˜ฌ๋ ธ๋‹ค ํ•˜๋Š” ์›์‹œ์ ์ธ ๋ฐฉ๋ฒ•์„ ์„ ํƒํ•˜๊ธฐ๋„ ํ–ˆ๊ตฌ์š”.

๊ทธ๋Ÿผ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  Redux๋ฅผ ์‚ฌ์šฉํ•  ์ค„ ์•„๋Š” ๊ฒƒ์€ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ์ปค๋ฎค๋‹ˆํ‹ฐ๊ฐ€ ํฌ๋‹ˆ๊นŒ์š”. ๊ธฐํšŒ๊ฐ€ ๋  ๋•Œ๋งˆ๋‹ค ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋Œ€ํ•œ ์งˆ๋ฌธ์„ ํ•ด ๋ณด๋ฉด, ํฐ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ์•„์ง Redux๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค๋Š” ๋‹ต๋ณ€์„ ๋“ฃ๊ณค ํ•ฉ๋‹ˆ๋‹ค. ๋˜ ์ฃผ๋ณ€์˜ Redux๋งจ๋“ค์—๊ฒŒ ๋ฌผ์–ด๋ณด๋ฉด ๋ช‡ ๋ฒˆ ๊ฒช์–ด๋ณด๋ฉด ๊ธˆ๋ฐฉ ์ต์ˆ™ํ•ด์ง„๋‹ค๊ณ  ํ•˜๋‹ˆ, ์ฒซ ๊ณ ๋น„๋ฅผ ๋„˜๊ธฐ๊ณ  ๋‚˜๋ฉด ์ž˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€ ์•Š์„๊นŒ.. ๊ทธ๋Ÿฐ ๊ธฐ๋Œ€๋ฅผ ํ•ด ๋ด…๋‹ˆ๋‹ค.

๐Ÿ”‹ Recoil

๋ฆฌ-ํ•˜(๋ฆฌ์ฝ”์ผ ํ•˜์ด๋ผ๋Š” ๋œป)

์ด๋ฒˆ์—” Recoil์„ ์ฒดํ—˜ํ•ด ๋ณผ ์ฐจ๋ก€์ž…๋‹ˆ๋‹ค. Recoil๋กœ ๋งํ•  ๊ฒƒ ๊ฐ™์œผ๋ฉด ๋ฆฌ์•กํŠธ๋ฅผ ๋งŒ๋“  ํŽ˜์ด์Šค๋ถ์ด ์ง์ ‘ ๊ณต๊ฐœํ•œ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค.

์šฐ๋ฆฌ ๋ชจ๋‘๊ฐ€ React๊ฐ€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ๋™์ž‘ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์ง€๋งŒ, ๋ฆฌ์•กํŠธ์™€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์กฐ๊ธˆ ๋‹ค๋ฅธ ์„ธ๊ณ„์ฒ˜๋Ÿผ ๋Š๊ปด์ง€๋Š” ๋ถ„๋“ค์ด ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋ฅผํ…Œ๋ฉด, React๋ฅผ ์œ„ํ•ด ๋งŒ๋“ค์–ด์ง„ ํŒจํ‚ค์ง€๋Š” React์—์„œ ์‚ฌ์šฉํ•˜๊ณ , VanilaJS๋ฅผ ์œ„ํ•ด ๋งŒ๋“ค์–ด์ง„ ํŒจํ‚ค์ง€๋Š” VanilaJS์—์„œ๋ฐ–์— ์“ธ ์ˆ˜ ์—†๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์ƒ๊ฐํ•˜๋Š” ๋ถ„๋“ค์ด ์žˆ์ฃ .

Untitled

์ด๋Ÿฐ ๊ฑฐ๋ฆฌ๊ฐ๋•Œ๋ฌธ์— ๋งŽ์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ์ง์ ‘ โ€˜React์Šค๋Ÿฌ์šดโ€™ ๋ฐฉ์‹์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค. ์œ„ ์‚ฌ์ง„์€ ์ €๋ฒˆ ํ”„๋กœ์ ํŠธ์—์„œ ์‚ฌ์šฉํ–ˆ๋˜ ์บ”๋ฒ„์Šค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ konva์˜ ๋ฆฌ์•กํŠธ ๋ฒ„์ „, react-konva ์ฝ”๋“œ ์ผ๋ถ€์ž…๋‹ˆ๋‹ค.

์ œ๊ฐ€ ์ด ์ด์•ผ๊ธฐ๋ฅผ ์™œ ํ•˜๋Š” ๊ฒƒ์ผ๊นŒ์š”? Recoil์€, ์˜ค์ง React๋งŒ์„ ์œ„ํ•ด ๋งŒ๋“ค์–ด์ง„ React ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ด ์ ์„ ๊ฐ€์žฅ ํฐ ํŠน์ง•์œผ๋กœ ๋ง์”€๋“œ๋ฆด ์ˆ˜ ์žˆ๊ฒ ๋„ค์š”. ๊ทธ ์™ธ์—๋„ atom ๊ตฌ์กฐ๋ฅผ ํ†ตํ•ด์„œ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌ ์–ด์ฉŒ๊ตฌ.. ํ•˜๋Š” ์ž‘๋™ ๋ฐฉ์‹์— ๋Œ€ํ•œ ๋‚ด์šฉ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ธ€์—์„œ ํ•˜์ง€ ์•Š๊ธฐ๋กœ ํ•œ ์ด์•ผ๊ธฐ๋„ค์š”.

์‚ฌ์šฉํ•ด ๋ด…์‹œ๋‹ค

npm i recoil

์„ค์น˜ํ•ด ์ค๋‹ˆ๋‹ค. redux์™€ ๋น„๊ตํ–ˆ์„ ๋•Œ ๋ณ„๋‹ค๋ฅธ ์„ค์น˜๋ฅผ ์š”๊ตฌํ•˜์ง€ ์•Š๊ธด ํ•œ๋ฐ, ํ .. ๋ณ„ ์ƒ๊ฐ์€ ๋“ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

// atom.ts
import { atom } from "recoil";

const counterState = atom({
  key: "count",
  default: 0,
});

export default counterState;

redux์˜ reducer์™€ ๋น„์Šทํ•œ ์—ญํ• ์„ ํ•˜๋Š” atom์„ ์„ ์–ธํ•ด ์ค๋‹ˆ๋‹ค. reducer๋Š” ์ดˆ๊ธฐ ๊ฐ’๊ณผ action๊นŒ์ง€ ๋ชจ๋‘ ์ •์˜ํ–ˆ์ง€๋งŒ, atom์€ key์™€ default value๋งŒ ์ง€์ •ํ•ด์„œ exportํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

// App.tsx
...
export default function App() {
  return (
    <React.StrictMode>
      <RecoilRoot>
        <Router>
          <Routes>
            <Route path="/" element={<Test />} />
            <Route path="/login" element={<Login />} />
          </Routes>
        </Router>
      </RecoilRoot>
    </React.StrictMode>
  );
}

redux์˜ Provider์ฒ˜๋Ÿผ ์—ญ์‹œ RecoilRoot๋ฅผ ํ†ตํ•ด atom์„ ์‚ฌ์šฉํ•  ์˜์—ญ์„ ๋ฌถ์–ด ์ค๋‹ˆ๋‹ค. ๋ณ„๋‹ค๋ฅธ store๋ฅผ ์ง€์ •ํ•˜์ง€ ์•Š๋„๋ก ๋˜์–ด ์žˆ๋Š”๋ฐ, ๊ฐ๊ฐ์˜ RecoilRoot๋Š” ๋ชจ๋“  atom์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ์–‘์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์—ฌ๋Ÿฌ RecoilRoot๋Š” ์„œ๋กœ atom ๊ฐ’์„ ๊ณต์œ ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—, ์—ฌ๋Ÿฌ ๊ฐœ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์–ด๋Š ์˜์—ญ์— ์žˆ๋Š”์ง€๋ฅผ ์ž˜ ์ฒดํฌํ•  ํ•„์š”๊ฐ€ ์žˆ๊ฒ ๋„ค์š”. ๊ผญ ๋ฉ€ํ‹ฐ๋ฒ„์Šค..๊ฐ™์Šต๋‹ˆ๋‹ค.

// TestRecoil.tsx
import React from 'react';
import { useRecoilState } from 'recoil';
import counterState from './recoil/atom';

export default function Test() {
  const [count, setCount] = useRecoilState(counterState);
	return (
	...
	<button type="button"
	onClick={() => {
		setCount(count - 1);
	}}
	>-</button>
	...
	);
}

Recoil์€ useState ํ›…๊ณผ ๊ฐ™์€ ์‚ฌ์šฉ๋ฒ•์„ ๊ฐ–์Šต๋‹ˆ๋‹ค. import๋งŒ ์ž˜ ํ•ด์คฌ๋‹ค๋ฉด, useRecoilState๋ฅผ ํ†ตํ•ด atom์„ ์‚ฌ์šฉํ•˜๊ฒ ๋‹ค ์„ ์–ธํ•˜๊ณ  ๋ฐ”๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Recoil์˜ ๊ฐ•์ ์ด ๋“œ๋Ÿฌ๋‚˜๋Š” ๋ถ€๋ถ„์ด๋„ค์š”. ์ฐธ์กฐ๋งŒ ํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” useRecoilValue, ํ• ๋‹น๋งŒ ํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” useSetRecoilState ๋ฅผ ํ†ตํ•ด ํ•œ ์ชฝ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฆฌ์ฝ”์ผ.gif

๊ฒฐ๊ณผ๋ฌผ์€ Redux์™€ ๋˜‘๊ฐ™์ด ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ Recoil ์“ฐ๋‚˜์š”?

์žฅ์ 

  • React์Šค๋Ÿฌ์›€
  • atom์˜ ์„ ์–ธ์ด ๊ฐ„๋‹จํ•˜๋‹ค

๋‹จ์ 

  • ์•„์ง ์‹คํ—˜์  ๊ธฐ๋Šฅ(experimental feature)์ด๋‹ค
  • ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฌธ์ œ
  • React์— ์ข…์†์ ์ด๋‹ค.

๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค. ์š”์•ฝ๋งŒ ๋ด๋„ ๋Š๊ปด์ง€์ง€๋งŒ Recoil์€ ๊ทธ๋ ‡๊ฒŒ ์•ˆ์ •์ ์ธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ์šฐ์„  ๋ ˆํฌ์ง€ํ† ๋ฆฌ ์ž์ฒด๊ฐ€ facebookexperimental์— ์žˆ๊ณ , issue์— ๊ฒ€์ƒ‰ํ•ด๋ณด๋ฉด ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜์— ๋Œ€ํ•œ ๋ ˆํฌํŠธ๊ฐ€ ๊ฝค ๋งŽ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๋ฌธ์ œ ๋•Œ๋ฌธ์— Recoil์€ ์•„์ง๊นŒ์ง€๋„ โ€˜๋ฆฌ์•กํŠธ์Šค๋Ÿฝ๋‹คโ€™๋Š” ์••๋„์ ์ธ ๊ฐ•์ ์„ ๊ฐ€์ง€๊ณ ๋„ ๊ทธ๋ ‡๊ฒŒ ์ข‹์€ ์„ฑ์ ์„ ๋‚ด์ง€ ๋ชปํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์‹ค์ œ ์„œ๋น„์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋Š”๋ฐ โ€˜์‹คํ—˜์  ๊ธฐ๋Šฅโ€™์— ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ๋ฏฟ๊ณ  ๋งก๊ธธ ์ˆ˜ ์žˆ์„๊นŒ์š”? React๋ฅผ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋‹ค ๋ณด๋‹ˆ React ์ƒํƒœ๊ณ„์—์„œ ๋ฒ—์–ด๋‚œ๋‹ค๋ฉด ๋˜ ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๊ณต๋ถ€ํ•ด์•ผ ํ•œ๋‹ค๋Š” ์ ๋„ ๋ฌธ์ œ๊ฐ€ ๋  ๊ฒƒ ๊ฐ™๋„ค์š”. ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฌธ์ œ์— ๋Œ€ํ•ด ๋” ์ž์„ธํžˆ ์•Œ๊ณ  ์‹ถ์œผ์‹œ๋ฉด ์ด ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

ํ•˜์ง€๋งŒ Recoil์€ ๋ถ„๋ช… ๋งค๋ ฅ์ ์ž…๋‹ˆ๋‹ค. ํŠนํžˆ React๋ฅผ ํ†ตํ•ด ๊ตฌํ˜„ํ•œ๋‹ค๋ฉด Recoil์˜ ๋งค๋ ฅ์„ ๋ฟŒ๋ฆฌ์น˜๊ธฐ๋ž€ ์‰ฝ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์™œ๋ƒ๋ฉด Recoil์€ React์Šค๋Ÿฌ์šฐ๋‹ˆ๊นŒ์š”. useState๋ฅผ ์“ฐ๋Š” ๊ฒƒ๊ณผ ์™„์ „ ๋˜‘๊ฐ™์ด ์ „์—ญ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค๋‹ˆ, ์ด ํŠน์„ฑ ํ•˜๋‚˜๋งŒ์œผ๋กœ๋„ ์„ ํƒํ•  ์ด์œ ๋Š” ์ถฉ๋ถ„ํ•ด ๋ณด์ž…๋‹ˆ๋‹ค.

โ“ ๊ทธ๋ž˜์„œ ๋ญ ์“ฐ๋‚˜์š”?

Untitled

Redux์™€ Recoil์— ๋Œ€ํ•ด ์•Œ์•„๋ดค์Šต๋‹ˆ๋‹ค. ์‚ฌ์‹ค ์šฐ๋ฆฌ ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ ํƒํ•˜๊ธฐ ์œ„ํ•ด ๊ณต๋ถ€ํ–ˆ๋Š”๋ฐ, ๊ณต๋ถ€ํ•˜๊ณ  ๋‚˜๋‹ˆ ๋” ๋ณต์žกํ•ด์ง€๋„ค์š”. ํ•˜์ง€๋งŒ ์–ด๋Š ํ•œ ์ชฝ์ด โ€˜์ข‹๋‹คโ€™๊ณ  ๊ฒฐ๋ก ์ง€์„ ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ œ๋Š” ์•„๋‹ˆ๊ณ  ํŒฅ๋ถ•์„ ๋จน์„์ง€ ์Šˆ๋ถ•์„ ๋จน์„์ง€, ๊ทธ ๋‚ ์˜ ๊ธฐ๋ถ„์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง€๋Š” ๊ทธ๋Ÿฐ ์„ ํƒ์ผ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ฐธ๊ณ ๋กœ ์ €๋Š” ํŒฅ์„ ์‹ซ์–ดํ•ฉ๋‹ˆ๋‹ค.

์•ž์œผ๋กœ์˜ ํ”„๋กœ์ ํŠธ์—์„œ ์ œ๊ฐ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๊ณ ๋ฅธ๋‹ค๋ฉด ์–ด๋–ค ๊ธฐ์ค€์œผ๋กœ ์ •ํ•  ์ˆ˜ ์žˆ์„๊นŒ์š”? ์ €๋Š” ํ”„๋กœ์ ํŠธ์˜ ๊ทœ๋ชจ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๊ฒฐ์ •ํ•  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์‚ฌ์‹ค Redux๋Š” ์•ˆ์ •์ ์ด์ง€๋งŒ ํ† ์ด ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•˜๊ธฐ์—๋Š” ๋„ˆ๋ฌด ๋งŽ์€ ๋ฐ‘์ž‘์—…์„ ํ•„์š”๋กœ ํ•˜๊ฑฐ๋“ ์š”. ๋ฐ˜๋ฉด ์ปค๋‹ค๋ž€ ํ”„๋กœ์ ํŠธ๋ฅผ ํ•ด์•ผ ํ•œ๋‹ค๋ฉด Redux๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•  ๋‚ ์ด ์˜ฌ ์ˆ˜๋„ ์žˆ๊ฒ ์ฃ . ๋ง๋ถ™์ด์ž๋ฉด ์ปดํผ๋‹ˆ๋ฐ์ด ๋•Œ ์–ด๋–ค ๊ธฐ์—…์—์„œ๋Š” Redux์™€ Recoil์„ ํ•จ๊ป˜ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ๋‹ต๋ณ€์„ ์ฃผ์‹œ๊ธฐ๋„ ํ–ˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“– Refs.

TypeScript and redux tool kit , createSlice: Assignment to property of function parameter ‘state’
Getting Started with Redux
๋งค๊ฐœ๋ณ€์ˆ˜ ์žฌํ• ๋‹น์„ ์ง€์–‘ํ•˜์ž(no-param-reassign)
Redux Toolkit with Typescript: How to Get Started
RecoilRoot | Recoil
React์Šค๋Ÿฌ์šด ์ƒํƒœ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ, Recoil์„ ์•Œ์•„๋ณด์ž
Recoil์˜ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฌธ์ œ
๊ทธ๋ฆฌ๊ณ  ๋ถ€์ŠคํŠธ์บ ํ”„ ์ปจํผ๋Ÿฐ์Šค๋ฅผ ํ†ตํ•ด Recoil์— ๋Œ€ํ•ด ์„ค๋ช…ํ•ด ์ฃผ์‹  J039 ๊น€์„ฑ์€ ์บ ํผ๋‹˜๊ป˜ ๊ฐ์‚ฌ์˜ ์ธ์‚ฌ๋ฅผ ์˜ฌ๋ฆฝ๋‹ˆ๋‹ค. ๐Ÿ™‡