ํ”„๋กœ๊ทธ๋ž˜๋ฐ/React JS

[React] ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋Œ€ํ•œ ๊ณ ์ฐฐ (feat. redux-tookit, recoil, zustand, jotai)

์šฉ๋‡ฝ 2024. 3. 25. 22:16
๋ฐ˜์‘ํ˜•

[React] ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋Œ€ํ•œ ๊ณ ์ฐฐ (feat. redux-tookit, recoil, zustand, jotai)

๐Ÿ“– ๋“ค์–ด๊ฐ€๋ฉฐ

์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” React์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์ƒํƒœ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋Œ€ํ•ด์„œ ๊ฐ๊ฐ์˜ ํŠน์ง•๊ณผ ๊ฐœ์ธ์ ์ธ ๊ฒฌํ•ด๊ฐ€ ๋“ค์–ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

 

ํ˜„์žฌ ํฌ์ŠคํŒ…์—์„œ ๋‹ค๋ฃฐ ์ฃผ์š” ๋„ค ๊ฐ€์ง€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค.

  • react-redux & redux-toolkit
  • recoil
  • zustand
  • jotai

React์—์„œ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ํ•จ๊ป˜ ๊ฐœ๋ฐœ์„ ํ•˜๋‹ค ๋ณด๋ฉด ์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ๋„ค ๊ฐ€์ง€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ค‘ ํ•˜๋‚˜์ฏค์€ ๋ถ„๋ช… ์•Œ๊ณ  ๊ณ„์‹œ๋ฆฌ๋ผ ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์ƒํƒœ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ NPM Trends

์œ„ ์ด๋ฏธ์ง€๋Š” ์ตœ๊ทผ 1๋…„๊ฐ„ ๋„ค ๊ฐ€์ง€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ NPM ๋™ํ–ฅ์ž…๋‹ˆ๋‹ค.

 

ํ˜„์žฌ ์ถ”์„ธ๋กœ ๋ดค์„ ๋•Œ

1์œ„: redux (react-redux & redux-tookit)

2์œ„: zustand

3์œ„: jotai

4์œ„: recoil

์œ„ ์ˆœ์œ„๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.

 

๊ทธ๋Ÿผ ๊ฐ„๋‹จํ•œ ์ฝ”๋“œ ์˜ˆ์ œ์™€ ํ•จ๊ป˜ ํŠน์ง•์„ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

Redux (react-redux & redux-toolkit)

Redux (react-redux & redux-toolkit)

Redux์˜ ์ฃผ์š” ์•„์ด๋””์–ด๋Š” ์ „์ฒด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ƒํƒœ๊ฐ€ ๋‹จ์ผ ์ „์—ญ "store"์— ์ €์žฅ๋˜๊ณ  ์ƒํƒœ ์ˆ˜์ •์€ ์ €์žฅ์†Œ์— ์ „๋‹ฌ๋˜๋Š” "action"์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค.

 

๊ทธ๋Ÿฐ ๋‹ค์Œ ์ €์žฅ์†Œ๋Š” ์ด๋Ÿฌํ•œ ์ž‘์—…์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ณ  ์ด๋ฅผ ํ•„์š”๋กœ ํ•˜๋Š” React ๊ตฌ์„ฑ ์š”์†Œ์— ์—…๋ฐ์ดํŠธ๋œ ์ƒํƒœ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

 

์ด ์•„ํ‚คํ…์ฒ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ณต์žกํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ƒํƒœ๋ฅผ ๋” ์‰ฝ๊ฒŒ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋™์ž‘์„ ์˜ˆ์ธก ๊ฐ€๋Šฅํ•˜๊ณ  ์‰ฝ๊ฒŒ ๋””๋ฒ„๊น…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

Redux๋Š” Flux ํŒจํ„ด์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘ํ•˜๋Š” ์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค.

 

์—ฌ๊ธฐ์„œ๋Š” redux-toolkit์„ ๊ธฐ์ค€์œผ๋กœ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

redux-toolkit์„ ๊ธฐ์ค€์œผ๋กœ ์•Œ์•„๋ณด๋Š” ์ด์œ ๋Š” redux ๊ณต์‹๋ฌธ์„œ์—์„œ๋„ redux-toolkit์„ ์ถ”์ฒœํ•˜๊ณ  ์žˆ๊ณ , ๊ธฐ์กด์˜ redux์˜ ๋ฌธ์ œ์ ์„ ๋ณด์™„ํ•˜๋ฉด์„œ ํšจ์œจ์ ์ธ redux ๊ฐœ๋ฐœ์„ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๊ธฐ์กด์˜ ๋ฌธ์ œ์ 

  • Redux ์Šคํ† ์–ด์˜ ๊ตฌ์„ฑ์ด ๋ณต์žกํ•จ
  • Redux๋กœ ์œ ์šฉํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋งŽ์€ ํŒจํ‚ค์ง€๊ฐ€ ์ถ”๊ฐ€๋กœ ํ•„์š”ํ•จ
  • ๋ถˆํ•„์š”ํ•˜๊ฒŒ ๋งŽ์€ ๋ณด์ผ๋Ÿฌํ”Œ๋ ˆ์ดํŠธ ์ฝ”๋“œ

redux-tookit์œผ๋กœ ์ž‘์„ฑํ•œ counter ๊ธฐ๋Šฅ์„ ํ•˜๋Š” ์ฝ”๋“œ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

redux๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด Provider๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ์‹ธ์ค€ ๋’ค store๋ฅผ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.tsx';
import './index.css';
import { store } from './store';
import { Provider } from 'react-redux';

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

 

์ดํ›„, ์•„๋ž˜์™€ ๊ฐ™์ด slice๋ฅผ ์ƒ์„ฑํ•˜์—ฌ reducer๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

//features/counter/countSlice.tsx
import { createSlice } from '@reduxjs/toolkit';
import type { PayloadAction } from '@reduxjs/toolkit';

export interface CounterState {
  value: number;
}

const initialState: CounterState = {
  value: 0,
};

export const counterSlice = createSlice({
  name: 'counter',
  initialState,
  reducers: {
    increment: (state) => {
      state.value += 1;
    },
    decrement: (state) => {
      state.value -= 1;
    },
    incrementByAmount: (state, action: PayloadAction<number>) => {
      state.value += action.payload;
    },
  },
});

export const { increment, decrement, incrementByAmount } = counterSlice.actions;

export default counterSlice.reducer;
//store.ts
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './features/counter/counterSlice';

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

// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>;
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch;

 

์œ„์™€ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•œ ๋’ค์—, ์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// App.tsx
import './App.css';
import { useDispatch, useSelector } from 'react-redux';
import { RootState } from './store';
import { decrement, increment } from './features/counter/counterSlice';

function App() {
  const count = useSelector((state: RootState) => state.counter.value);
  const dispatch = useDispatch();

  const onIncrementButtonClick = () => dispatch(increment());

  const onDecrementButtonClick = () => dispatch(decrement());

  return (
    <>
      <h1>๋ฆฌ์•กํŠธ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์˜ˆ์ œ</h1>
      <div className="card">
        <button onClick={onIncrementButtonClick}>Increment value</button>
      </div>
      <span>{count}</span>
      <div className="card">
        <button onClick={onDecrementButtonClick}>Decrement value</button>
      </div>
    </>
  );
}

export default App;

ํŠน์ง• ๐Ÿง

๊ฐ„๋‹จํ•œ counter ๊ธฐ๋Šฅ์„ ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐ ์žˆ์–ด์„œ ๊ทธ๋ž˜๋„ ์ฝ”๋“œ๋Ÿ‰์ด ๋งŽ์€ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๋Œ€์‹ ์— ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ค‘ redux๊ฐ€ ๊ฐ€์žฅ ์—ญ์‚ฌ๊ฐ€ ์˜ค๋ž˜๋˜์—ˆ๊ณ , redux์— ์˜๊ฐ์„ ๋ฐ›์•„ ํŒŒ์ƒ๋œ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

 

์ด ๋œป์€ ๊ทธ๋งŒํผ ๊ฒ€์ฆ๋œ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๊ณ , redux๋กœ ๊ฐœ๋ฐœํ•  ๋•Œ ์ฐธ๊ณ  ์ž๋ฃŒ๊ฐ€ ์ •๋ง ๋งŽ์Šต๋‹ˆ๋‹ค.

 

ํ•˜์ง€๋งŒ Redux ์ž์ฒด์˜ ๊ฐœ๋…์„ ์ดํ•ดํ•˜๋Š” ๋ฐ ๋Ÿฌ๋‹ ์ปค๋ธŒ๋Š” ์ƒ๋Œ€์ ์œผ๋กœ ๋†’์Šต๋‹ˆ๋‹ค.

๋Œ€์‹ , Flux ํŒจํ„ด์„ ์ดํ•ดํ•˜๋Š” ๋ฐ ๋งŽ์€ ๋„์›€์ด ๋œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

 

๊ทธ๋ฆฌ๊ณ  Redux-toolkit ์—ญ์‹œ Redux์˜ ๊ธฐ๋ณธ์„ ์•Œ์•„์•ผ ํšจ๊ณผ์ ์œผ๋กœ ์ž˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

 

๋˜ํ•œ, redux-toolkit์— RTK-query(์„œ๋ฒ„ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ)๋„ ๋‚ด์žฅ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ณ„๋„์˜ ์„ค์น˜ ์—†์ด ์„œ๋ฒ„ ๋ฐ์ดํ„ฐ๋ฅผ ์บ์‹ฑํ•˜๋Š” ๋ฐ์— ์žˆ์–ด์„œ redux์™€ ์ž˜ ํ˜ธํ™˜์ด ๋ฉ๋‹ˆ๋‹ค.

 

ํ•˜์ง€๋งŒ ๋ฐ˜๋Œ€๋กœ ์ƒ๊ฐํ•ด ๋ณด๋ฉด ์„œ๋ฒ„ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ์ƒํƒœ ๊ด€๋ฆฌ๊ฐ€ ํ•„์š” ์—†์„ ๋•Œ์—๋Š” ํŒจํ‚ค์ง€ ์šฉ๋Ÿ‰๋งŒ ๋ถˆํ•„์š”ํ•˜๊ฒŒ ์ฆ๊ฐ€ํ•˜๋Š” ๊ผด์ด ๋˜์–ด๋ฒ„๋ฆฌ์ฃ .

 

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

 

๊ทธ๋ฆฌ๊ณ  ๋นผ๋†“์„ ์ˆ˜ ์—†๋Š” ํฐ ์žฅ์  ์ค‘ ํ•˜๋‚˜๋Š” redux-dev-tools๋ฅผ ํ†ตํ•ด์„œ ์ƒํƒœ ๊ด€๋ฆฌ์˜ ๋””๋ฒ„๊น…์— ์žˆ์–ด์„œ ๋งค์šฐ ํŽธ๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

rtk npm

npm์—์„œ ํ™•์ธํ•œ ๊ฒฐ๊ณผ๋กœ๋Š” ์šฉ๋Ÿ‰์€ 5.51MB๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๊ณ , ์ตœ๊ทผ ๋ฐฐํฌ๋Š” 4์ผ ์ „์— ์ง„ํ–‰๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฆ‰, ์šฉ๋Ÿ‰์€ ์ƒ๋Œ€์ ์œผ๋กœ ํฌ๊ณ , ์œ ์ง€๋ณด์ˆ˜๋Š” ๊พธ์ค€ํžˆ ๋˜๊ณ  ์žˆ๋‹ค๋Š” ๊ฑธ๋กœ ํ•ด์„ํ•  ์ˆ˜ ์žˆ๊ฒ ๋„ค์š”.

 

๊ฐ„๋‹จํ•˜๊ฒŒ ์ •๋ฆฌํ•ด๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • Redux๋Š” ์ถฉ๋ถ„ํžˆ ๊ฐ•๋ ฅํ•œ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋‹ค. (middleware, devTools ๋“ฑ)
  • ์ฐธ๊ณ ์ž๋ฃŒ๊ฐ€ ๋งŽ๋‹ค.
  • ๋Ÿฌ๋‹์ปค๋ธŒ๊ฐ€ ๋†’๋‹ค.
  • redux-toolkit์„ ์‚ฌ์šฉํ•ด๋„ ์ฝ”๋“œ๋Ÿ‰์ด redux์— ๋น„ํ•ด ์ ์–ด์ง„ ๊ฒƒ์ด์ง€ ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์— ๋น„ํ•ด ์ƒ๋Œ€์ ์œผ๋กœ ๋งŽ๋‹ค.
  • Redux์˜ ๋‹จ์ ์„ ๊ฑท์–ด๋‚ผ ์ˆ˜ ์žˆ๋Š” ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์ด ๋“ฑ์žฅํ–ˆ๋‹ค.

Recoil

recoil

Recoil์€ FaceBook(ํ˜„ Meta)์—์„œ ๋ฐœํ‘œํ•œ React๋ฅผ ์œ„ํ•œ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค.

React๋ฅผ ๊ฐœ๋ฐœํ•œ ๊ธฐ์—…์—์„œ ๊ฐœ๋ฐœํ•˜๋Š” React๋ฅผ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋งŽ์€ ๊ฐœ๋ฐœ์ž๋“ค์ด ๊ธฐ๋Œ€๊ฐ์„ ๊ฐ€์กŒ๋˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค.

 

์‚ฌ์šฉ ๋ฐฉ๋ฒ•์ด ๋งค์šฐ ๊ฐ„๋‹จํ•˜๊ณ  React Hooks์™€ ์œ ์‚ฌํ•˜๊ฒŒ ๋™์ž‘ํ•˜์—ฌ React Hooks์— ์ต์ˆ™ํ•˜๋‹ค๋ฉด ๋Ÿฌ๋‹ ์ปค๋ธŒ๊ฐ€ ๋งค์šฐ ๋‚ฎ์Šต๋‹ˆ๋‹ค.

 

๊ธฐ๋ณธ์ ์œผ๋กœ ์ƒํƒœ๋ฅผ ์›์ž(atom)๋ผ๋Š” ์ž‘์€ ๋‹จ์œ„๋กœ ์ทจ๊ธ‰์„ ํ•˜๋ฉฐ ์ž‘์€ ์ƒํƒœ๋ฅผ ์กฐํ•ฉํ•˜์—ฌ ํฐ ์ƒํƒœ๋ฅผ ๋งŒ๋“ค๊ณ ,

์ƒํƒœ์—์„œ ๋‹ค๋ฅธ ์ƒํƒœ๋ฅผ ํŒŒ์ƒํ•˜๊ฑฐ๋‚˜ Selector์™€ ๊ฐ™์€ ์ˆœ์ˆ˜ ํ•จ์ˆ˜๋ฅผ ์ œ๊ณตํ•˜๋ฉฐ bottom-up ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

 

์•„๋ž˜๋Š” ๊ฐ„๋‹จํ•œ counter ๊ธฐ๋Šฅ์„ ํ•˜๋Š” ์ฝ”๋“œ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

 

Recoil ๋˜ํ•œ Provider ์ปดํฌ๋„ŒํŠธ๋กœ ๊ฐ์‹ธ์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

// main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.tsx';
import './index.css';
import { RecoilRoot } from 'recoil';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <RecoilRoot>
      <App />
    </RecoilRoot>
  </React.StrictMode>
);

atom ์ƒํƒœ์˜ ๋‹จ์œ„์ด๋ฉฐ, ์—…๋ฐ์ดํŠธ์™€ ๊ตฌ๋…์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ atom์ด ์—…๋ฐ์ดํŠธ๋˜๋ฉด ๊ฐ๊ฐ ๊ตฌ๋…๋œ ์ปดํฌ๋„ŒํŠธ๋Š” ์ƒˆ๋กœ์šด ๊ฐ’์„ ๋ฐ˜์˜ํ•˜์—ฌ ๋‹ค์‹œ ๋ Œ๋”๋ง ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๊ตฌ๋ณ„ํ•˜๊ธฐ ์œ„ํ•œ ๊ณ ์œ ์˜ key๊ฐ’์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

// features/counter/atom.ts

import { atom } from 'recoil';

export const countState = atom<number>({
  key: 'countState',
  default: 0,
});

 

์‚ฌ์šฉํ•˜๋Š” ๊ณณ์—์„œ๋Š” useState์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ useRecoilState๋ฅผ ํ†ตํ•ด์„œ ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•ด์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// App.tsx
import './App.css';
import { useRecoilState } from 'recoil';
import { countState } from './features/counter/atom';

function App() {
  const [count, setCount] = useRecoilState(countState);

  const onIncrementButtonClick = () => setCount((count) => count + 1);

  const onDecrementButtonClick = () => setCount((count) => count - 1);

  return (
    <>
      <h1>๋ฆฌ์•กํŠธ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์—์ œ</h1>
      <div className="card">
        <button onClick={onIncrementButtonClick}>Increment value</button>
      </div>
      <span>{count}</span>
      <div className="card">
        <button onClick={onDecrementButtonClick}>Decrement value</button>
      </div>
    </>
  );
}

export default App;

ํŠน์ง• ๐Ÿง

๋งค์šฐ ์ ์€ ์ฝ”๋“œ๋กœ ์ „์—ญ ์ƒํƒœ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Œ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๊ทธ๋ฆฌ๊ณ  ์ง๊ด€์ ์ธ ์ฝ”๋“œ๋กœ ์ธํ•ด์„œ ๋ณต์žกํ•œ ๋กœ์ง์— ๋Œ€ํ•ด์„œ๋„ ๊ฐ€๋…์„ฑ์„ ํฌ๊ฒŒ ๊ฐ€์ ธ๊ฐˆ ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

 

์œ„ ์˜ˆ์ œ์—์„œ๋Š” atom๋งŒ ์‚ฌ์šฉํ–ˆ์ง€๋งŒ recoil์˜ selectors๋ฅผ ์ด์šฉํ•ด์„œ atom์— ๋Œ€ํ•œ ํŒŒ์ƒ๋œ ์ƒํƒœ๋ฅผ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ, ๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ์— ๊ด€๋ จํ•ด์„œ๋„ ๊ด€๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

 

๋‹จ์ ์œผ๋กœ๋Š” redux-dev-tools์™€ ๊ฐ™์€ ๋””๋ฒ„๊น… ํˆด์ด ์™„๋ฒฝํ•˜๊ฒŒ ์ง€์›๋˜์ง€ ์•Š๋Š” ์ ์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

NPM recoil

ํ•˜์ง€๋งŒ ํ˜„์žฌ ๊ด€๋ฆฌ๊ฐ€ ์ž˜ ๋˜๊ณ  ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

 

์ € ๋˜ํ•œ redux๋ฅผ ์‚ฌ์šฉํ•œ ์ดํ›„ recoil์— ๋Œ€ํ•œ ์‚ฌ์šฉ ๊ฒฝํ—˜์ด ๋งค์šฐ ์ข‹์•„์„œ recoil์˜ ์•ž์œผ๋กœ์˜ ๋ฐฉํ–ฅ์„ฑ์— ๋Œ€ํ•ด์„œ ๋งค์šฐ ๊ธฐ๋Œ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

 

2020๋…„์— ์ถœ์‹œํ–ˆ์ง€๋งŒ ๋ฒ„์ „๋„ ๋งค์šฐ ๋‚ฎ์„๋ฟ๋”๋Ÿฌ, ๋งˆ์ง€๋ง‰ ์—…๋ฐ์ดํŠธ๊ฐ€ 1๋…„ ์ „์ž…๋‹ˆ๋‹ค.

 

์ด๋Ÿฌํ•œ ์ด์œ ๋กœ recoil์˜ ์ตœ๊ทผ ๋‹ค์šด๋กœ๋“œ ํšŸ์ˆ˜๋„ ์ค„์–ด๋“ค๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

 

์ฃผ์š” ์›์ธ์œผ๋กœ recoil์˜ ์ดˆ๊ธฐ ์„ค๊ณ„๋ถ€ํ„ฐ ๊ฐœ๋ฐœ๊นŒ์ง€ ๋‹ด๋‹นํ•œ ๋ฉ”์ธ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ •๋ฆฌ ํ•ด๊ณ ๋ฅผ ๋‹นํ•œ ์˜ํ–ฅ์ด ํฐ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

 

recoil์˜ ์—ญ์‚ฌ๊ฐ€ ์˜ค๋ž˜๋œ ๊ฒƒ๋„ ์•„๋‹ˆ๋ผ, ์ฐธ๊ณ  ์ž๋ฃŒ๊ฐ€ ๋ถ€์กฑํ•œ ์ƒํ™ฉ์ž…๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ์ƒํ™ฉ์—์„œ ์—…๋ฐ์ดํŠธ๊ฐ€ ๋˜์ง€ ์•Š์œผ๋‹ˆ ์‚ฌ์‹ค์ƒ ์•ž์œผ๋กœ recoil์„ ์„ ํƒํ•  ์ด์œ ๋Š” ๋งค์šฐ ์ ๋‹ค๊ณ  ์ƒ๊ฐ๋ฉ๋‹ˆ๋‹ค.

 

์‹ค์ œ๋กœ ์ดํ›„ ์•„๋ž˜์—์„œ ์„ค๋ช…ํ•  jotai์—๊ฒŒ ๋ฐ€๋ฆฌ๋Š” ์ค‘์— ์žˆ์Šต๋‹ˆ๋‹ค.

Zustand

Zustand

Zustand๋Š” ๋…์ผ์–ด๋กœ '์ƒํƒœ'๋ฅผ ์˜๋ฏธํ•œ๋‹ค๊ณ  ํ•˜๋„ค์š”.

 

ํ˜„์žฌ ๋– ์˜ค๋ฅด๊ณ  ์žˆ๋Š” ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค.

 

๊ฐ„์†Œํ™”๋œ Flux ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋ฉฐ ์ž‘๊ณ  ๋น ๋ฅด๊ณ  ํ™•์žฅ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค.

 

๋‹ค๋ฅธ React ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์Šคํ† ์–ด๋ฅผ ์ฃผ์ž…ํ•  ๋•Œ Context API๋ฅผ ์‚ฌ์šฉํ•˜์ง€๋งŒ Zustand๋Š” ํด๋กœ์ €๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์Šคํ† ์–ด ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•จ์œผ๋กœ์จ ํŠน์ • ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์ข…์†์ ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค

 

์•„๋ž˜๋Š” counter ๊ธฐ๋Šฅ์„ ํ•˜๋Š” ์ฝ”๋“œ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

 

์•„๋ž˜์™€ ๊ฐ™์ด devtools๋กœ ๊ฐ์‹ธ์ฃผ๋ฉด redux-dev-tools๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋””๋ฒ„๊น…์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

// features/counter/store.ts
import { create } from 'zustand';
import { devtools } from 'zustand/middleware';

interface ICountStore {
  count: number;
  increment: () => void;
  decrement: () => void;
}

export const useCountStore = create<ICountStore>()(
  devtools((set) => ({
    count: 0,
    increment: () => set((state) => ({ count: state.count + 1 })),
    decrement: () => set((state) => ({ count: state.count - 1 })),
  }))
);
// App.tsx
import './App.css';
import { useCountStore } from './features/counter/store';

function App() {
  const { count, increment, decrement } = useCountStore();

  return (
    <>
      <h1>๋ฆฌ์•กํŠธ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์—์ œ</h1>
      <div className="card">
        <button onClick={increment}>Increment value</button>
      </div>
      <span>{count}</span>
      <div className="card">
        <button onClick={decrement}>Decrement value</button>
      </div>
    </>
  );
}

export default App;

ํŠน์ง• ๐Ÿง

Zustand๋Š” Provider๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ์‹ธ์ฃผ์ง€ ์•Š์•„๋„ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

 

๋˜ํ•œ, ์ƒํƒœ์™€, ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ์•ก์…˜์„ ์ •์˜ํ•˜๊ณ , ๋ฆฌํ„ด ๋ฐ›์€ hook์„ ์–ด๋Š ์ปดํฌ๋„ŒํŠธ์—์„œ๋‚˜ import ํ•˜์—ฌ ์›ํ•˜๋Š” ๋Œ€๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

Redux์™€ ๊ฐ™์€ Flux ํŒจํ„ด์œผ๋กœ ๋™์ž‘ํ•˜๋Š”๋ฐ, ๋งค์šฐ ์ ์€ ์ฝ”๋“œ์–‘์œผ๋กœ ๊ฐœ๋ฐœ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

NPM zustand

NPM ๊ธฐ์ค€ ์šฉ๋Ÿ‰์€ 327kb๋กœ ๋งค์šฐ ์ ์Šต๋‹ˆ๋‹ค.

์ตœ๊ทผ ์—…๋ฐ์ดํŠธ๋„ 2์ผ ์ „์ด๊ณ  ์•„์ฃผ ํ™œ๋ฐœํ•˜๊ฒŒ ์—…๋ฐ์ดํŠธ๊ฐ€ ์ง„ํ–‰๋˜๊ณ , ์ฃผ๊ฐ„ ๋‹ค์šด๋กœ๋“œ ํšŸ์ˆ˜๋„ ๋†’์€ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

Zustand๊ฐ€ Redux์™€ ContextAPI ๋ณด๋‹ค ๋‚˜์€ ์ด์œ ๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์ด ์„ค๋ช…ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

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

Flux ํŒจํ„ด์— ์ต์ˆ™ํ•˜๋‹ค๋ฉด ์ ์€ ์šฉ๋Ÿ‰๊ณผ ์ ์€ ์ฝ”๋“œ๋กœ ๋น ๋ฅด๊ฒŒ ๊ฐœ๋ฐœ์ด ๊ฐ€๋Šฅํ•œ Zustand์˜ ์‚ฌ์šฉ์„ ๊ณ ๋ คํ•ด๋ณด์ง€ ์•Š์„ ์ˆ˜๊ฐ€ ์—†๊ฒ ๋„ค์š”.

Jotai

jotai

Jotai๋Š” Recoil์— ์˜๊ฐ์„ ๋ฐ›์•„์„œ ๋“ฑ์žฅํ•œ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฉฐ ํ˜„์žฌ ๋– ์˜ค๋ฅด๊ณ  ์žˆ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค.

 

๊ทธ๋ž˜์„œ Jotai ๋˜ํ•œ atomic ํŒจํ„ด์„ ๋”ฐ๋ฅด๊ณ , React๋ฅผ ์œ„ํ•œ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋ฉฐ React Hooks์™€ ๋งค์šฐ ์œ ์‚ฌํ•˜๊ฒŒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

 

์•„๋ž˜๋„ ์—ญ์‹œ counter ๊ธฐ๋Šฅ์„ ํ•˜๋Š” ์ฝ”๋“œ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

// features/counter/atom.ts
import { atom } from 'jotai';

export const countAtom = atom(0);
// App.tsx
import './App.css';
import { useAtom } from 'jotai';
import { countAtom } from './features/counter/atom';

function App() {
  const [count, setCount] = useAtom(countAtom);

  const onIncrementButtonClick = () => setCount((count) => count + 1);

  const onDecrementButtonClick = () => setCount((count) => count - 1);

  return (
    <>
      <h1>๋ฆฌ์•กํŠธ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์—์ œ</h1>
      <div className="card">
        <button onClick={onIncrementButtonClick}>Increment value</button>
      </div>
      <span>{count}</span>
      <div className="card">
        <button onClick={onDecrementButtonClick}>Decrement value</button>
      </div>
    </>
  );
}

export default App;

ํŠน์ง• ๐Ÿง

์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด Recoil ๊ทธ๋ฆฌ๊ณ  React Hooks์™€ ๋งค์šฐ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

 

๋˜ํ•œ, Recoil๊ณผ ๋‹ค๋ฅธ ์ ์€ atom ์ž‘์„ฑ ์‹œ key๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š๊ณ , Provider ๋˜ํ•œ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.


Provider ๊ด€๋ จํ•ด์„œ๋Š” ํ•„์š”์— ๋”ฐ๋ผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ์‹ธ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์ถ”๊ฐ€์ ์œผ๋กœ atom์˜ callback ํ•จ์ˆ˜๋กœ get๊ณผ set์„ ์ธ์ž๋กœ ๋ฐ›์•„์„œ ํŒŒ์ƒ๋œ ์ƒํƒœ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๋˜ํ•œ, SSR, ๋น„๋™๊ธฐ, Family ๋“ฑ ๋‹ค์–‘ํ•œ ์œ ํ‹ธ๋ฆฌํ‹ฐ๊ฐ€ ์ง€์›๋ฉ๋‹ˆ๋‹ค.

 

 

NPM jotai

NPM์„ ํ™•์ธํ•ด ๋ณด๋ฉด ๋งค์šฐ ์ž‘์€ ํฌ๊ธฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๊ณ  ๊พธ์ค€ํžˆ ์—…๋ฐ์ดํŠธ๋„ ์ž˜ ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

 

์ฃผ๊ฐ„ ๋‹ค์šด๋กœ๋“œ ์—ญ์‹œ Recoil ๋ณด๋‹ค ์•ฝ 30๋งŒ ํšŒ ์ •๋„ ๋†’์€ ๊ฒƒ์œผ๋กœ ํ™•์ธ๋ฉ๋‹ˆ๋‹ค.

 

๋ฒ„์ „์„ ๋ณด๋ฉด ๋ฒŒ์จ 2+ ๋ฒ„์ „๊นŒ์ง€ ์—…๋ฐ์ดํŠธ๊ฐ€ ๋˜์—ˆ๋„ค์š”.

 

ํ•˜์ง€๋งŒ Jotai ์—ญ์‹œ ์ฐธ๊ณ  ์ž๋ฃŒ๊ฐ€ ๋ฐฉ๋Œ€ํ•˜์ง€ ์•Š๊ณ , ๊ณต์‹์ ์ธ DevTools ์ง€์›์ด ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ ์–ด๋–ค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ ํƒํ•ด์•ผ ํ• ๊นŒ?๐Ÿง

๊ฐœ์ธ์ ์ธ ๊ฒฌํ•ด๋กœ ์ตœ๊ทผ ๋™ํ–ฅ์„ ์‚ดํŽด๋ดค์„ ๋•Œ,

 

Redux โžก๏ธ Zustand 

Recoil, ContenxtAPI โžก๏ธ Jotai

 

์ •๋„๋กœ ๋Œ€์ฒด๋˜๊ณ  ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

 

๋Œ€์ฒด๋˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์˜ ํŠน์ง•์„ ์‚ดํŽด๋ณด๋ฉด ๋งค์šฐ ๊ฒฝ๋Ÿ‰ํ™”๋œ ํฌ๊ธฐ์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ,

์ตœ์†Œํ™”๋œ ์ฝ”๋“œ๋กœ ๊ธฐ์กด์˜ ์›ฌ๋งŒํ•œ ๊ธฐ๋Šฅ๋“ค์„ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ๊ณ  ๊พธ์ค€ํžˆ ๊ด€๋ฆฌ๋˜๊ณ  ์—…๋ฐ์ดํŠธ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋งŽ์€ ๊ด€์‹ฌ์„ ๋ฐ›๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์ถ”๊ฐ€์ ์œผ๋กœ Typescript๋ฅผ ์ง€ํ–ฅํ•œ๋‹ค๋Š” ํŠน์ง•๋„ ์žˆ์–ด์š”.

 

ํ•˜์ง€๋งŒ "์š”์ฆ˜ ๋Œ€์„ธ๋‹ค, ์œ ํ–‰์ด๋‹ค, ์ตœ์‹  ๊ธฐ์ˆ ์ด๋‹ค" ์ด๋Ÿฐ ํ๋ฆ„์— ํœฉ์“ธ๋ฆฌ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ํ”„๋กœ์ ํŠธ ํŠน์„ฑ์— ๋งž๊ฒŒ ์ž˜ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์€ ๋ถ„๋ช…ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

 

์˜ˆ๋ฅผ ๋“ค์–ด, ๋Œ€๊ทœ๋ชจ ํ”„๋กœ์ ํŠธ์—์„œ ๋งŽ์€ ๊ธฐ๋Šฅ์„ ์š”๊ตฌํ•˜์—ฌ ์ฐธ๊ณ  ์ž๋ฃŒ๊ฐ€ ๋งŽ์•„์•ผ ํ•˜๋Š” ๊ฒƒ์„ ์ค‘์š”ํ•˜๊ฒŒ ์ƒ๊ฐํ•˜๋ฉด Redux๋ฅผ ์„ ํƒํ•  ์ˆ˜๋„ ์žˆ๊ณ ์š”.

 

๋Œ€์‹  ๋ฐ˜๋Œ€๋กœ ์ƒ๊ฐํ•ด๋ณด๋ฉด, ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ๊ด€์‹ฌ๋ฐ›๋Š” ์ด์œ ์™€ ์šฐ์ƒํ–ฅ์ธ ์ถ”์„ธ์—๋„ ๋ถ„๋ช…ํ•œ ์ด์œ ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๊ฐœ์ธ์ ์œผ๋กœ๋Š” ํ‰์†Œ Recoil์„ ์‚ฌ์šฉํ•  ์ƒํ™ฉ์—๋Š” Jotai๋ฅผ ์„ ํƒํ•˜๊ฒŒ ๋  ๊ฒƒ ๊ฐ™๋„ค์š”.

๋˜ํ•œ, ํ˜„์žฌ ์ €๋Š” redux-toolkit์— ์ต์ˆ™ํ•˜์ง€๋งŒ ํŠน๋ณ„ํ•œ ์ด์œ ๊ฐ€ ์—†๋‹ค๋ฉด ์ดํ›„์— Zustand๋ฅผ ๊ฒฝํ—˜ํ•ด๋ณด๊ณ  ์‹ถ๋„ค์š”.

 

๋งˆ์ง€๋ง‰์œผ๋กœ ๊ฐ„๋‹จํ•˜๊ฒŒ ํ‘œ๋กœ ๋น„๊ตํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

2024๋…„ 3์›” 25์ผ ๊ธฐ์ค€์ž…๋‹ˆ๋‹ค.

๋น„๊ต redux-toolkit Recoil Zustand Jotai
ํฌ๊ธฐ (Unpacked Size) 5.51MB 2.21MB 327KB 430KB
์ฃผ๊ฐ„ ๋‹ค์šด๋กœ๋“œ ์ˆ˜ ์•ฝ 330๋งŒ ํšŒ ์•ฝ 60๋งŒ ํšŒ ์•ฝ 320๋งŒ ํšŒ ์•ฝ 90๋งŒ 
์œ ์ง€๋ณด์ˆ˜ ์ข‹์Œ ๋Š๋ฆผ ์ข‹์Œ ์ข‹์Œ
๊นƒํ—ˆ๋ธŒ start 10.3k 19.4k 41.5k 17k
๋ณต์žก๋„ ์ค‘๊ฐ„ ๋‚ฎ์Œ ๋‚ฎ์Œ ๋‚ฎ์Œ
์ฐธ๊ณ ์ž๋ฃŒ ๋†’์Œ ๋‚ฎ์Œ ์–‘ํ˜ธ ๋‚ฎ์Œ
Provider ํ•„์š” ํ•„์š”ํ•จ ํ•„์š”ํ•จ ํ•„์š”์—†์Œ ์„ ํƒ์ 
DevTools ์ง€์› โญ• โŒ โญ• โŒ

 

์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์— ๋Œ€ํ•œ ์„ธ๋Œ€๊ต์ฒด๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฑธ๊นŒ์š”?

 

๋งค์šฐ ํฅ๋ฏธ๋กญ์Šต๋‹ˆ๋‹ค.

 

์ด๋Ÿด์ˆ˜๋ก ์ €๋Š” ๊ฐœ๋ฐœ ํŽธ์˜์„ฑ, ์ƒ์‚ฐ์„ฑ ๋ชจ๋‘ ์ฆ๊ฐ€ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์„ ํƒ์ง€๊ฐ€ ๋„“์–ด์ง€๊ณ  ์ข‹์€ ์ž…์žฅ์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค :)

 

๊ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๊นŠ์ด ๋ณด๋‹ค๋Š” ๋Œ€ํ‘œ์ ์ธ ํŠน์ง•์— ๋Œ€ํ•ด์„œ๋งŒ ํ›‘์–ด๋ดค์Šต๋‹ˆ๋‹ค.

 

๋ถ€์ •ํ™•ํ•œ ์ •๋ณด๋‚˜, ์ถ”๊ฐ€ํ•˜๋ฉด ์ข‹์€ ๋‚ด์šฉ์ด ์žˆ์œผ๋ฉด ๋Œ“๊ธ€ ๋‚จ๊ฒจ์ฃผ์„ธ์š”. ๐Ÿ˜„

 

์ฐธ๊ณ  ๋ฌธํ—Œ:

๋ฐ˜์‘ํ˜•