๐Ÿ‘ฉโ€๐ŸŽจ Jotai ๋ž€?

๊น€์ˆ˜์ง„ยท2025๋…„ 6์›” 4์ผ

Jotai, ์™œ ํ•„์š”ํ• ๊นŒ?

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

์ด๋Ÿด ๋•Œ ์ƒํƒœ๊ด€๋ฆฌ๋ผ๋Š” ๊ฒŒ ํ•„์š”ํ•˜๋‹ค.

๊ทธ๋Ÿฐ๋ฐโ€ฆ

Redux๋Š” ๋„ˆ๋ฌด ๋ณต์žกํ•˜๊ณ 

Recoil์€ ๋ญ”๊ฐ€ ์–ด๋ ต๊ณ 

Context API๋Š” ์ƒํƒœ๊ฐ€ ๋งŽ์•„์ง€๋ฉด ๋ณต์žกํ•ด์ง€๊ณ โ€ฆ

๊ทธ๋ž˜์„œ ๋“ฑ์žฅํ•œ ๊ฒŒ Jotai์ด๋‹ค!

Jotai๋ž€?

Jotai๋Š” ์›์ž(atom) ๋‹จ์œ„๋กœ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” React ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋‹ค. ์ด๋ฆ„ ๋œป ๊ทธ๋Œ€๋กœ, ์ƒํƒœ๋ฅผ ๊ฐ€์žฅ ์ž‘์€ ์กฐ๊ฐ์œผ๋กœ ๋‚˜๋ˆ ์„œ ํ•„์š”ํ•  ๋•Œ๋งŒ ๊ฐ€์ ธ๋‹ค ์“ฐ๋Š” ๋ฐฉ์‹์ด๋‹ค.

๐Ÿ”ง ์„ค์น˜ ๋ฐฉ๋ฒ•

npm install jotai 

๐Ÿงฉ atom ?

atom์€ Jotai์—์„œ ์ƒํƒœ(state)๋ฅผ ์ž‘์€ ์กฐ๊ฐ์œผ๋กœ ๋‚˜๋ˆŒ๋•Œ, ์ด๋ฅผ ์ €์žฅํ•˜๋Š” ๊ฐ€์žฅ ์ž‘์€ ๋‹จ์œ„์ด๋‹ค.

๐Ÿ” Jotai ์‚ฌ์šฉ๋ฒ•

import { useAtom } from 'jotai';

function Counter() {
  const [count, setCount] = useAtom(countAtom); // ์—ฐ๊ฒฐ ์™„๋ฃŒ!

  return (
    <>
      <h1>{count}</h1> {/* countAtom์—์„œ ๊ฐ€์ ธ์˜จ ๊ฐ’ */}
      <button onClick={() => setCount(count + 1)}>+1</button> {/* countAtom์„ ์ˆ˜์ • */}
    </>
  );
}
import { useAtom } from 'jotai';

๐Ÿ‘‰ Jotai์—์„œ ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๊ผญ ํ•„์š”ํ•œ ์ฝ”๋“œ์ด๋‹ค.

๐Ÿ‘‰ useAtom()์€ useState()์ฒ˜๋Ÿผ ์ž‘๋™ํ•˜์ง€๋งŒ, ์ƒํƒœ๋ฅผ atom๊ณผ ์—ฐ๊ฒฐํ•ด์„œ ์‚ฌ์šฉํ•œ๋‹ค.

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

๐Ÿ‘‰ countAtom์€ ์•„๊นŒ ๋งŒ๋“  Jotai์˜ ์ƒํƒœ ์กฐ๊ฐ(์˜ˆ: const countAtom = atom(0))์ด๋‹ค.

๐Ÿ‘‰ useAtom(countAtom)์„ ์‚ฌ์šฉํ•˜๋ฉด:

count: ํ˜„์žฌ ์ƒํƒœ๊ฐ’์„ ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค. (์ดˆ๊ธฐ๊ฐ’์€ 0)
setCount: ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜์ด๋‹ค.

โš ๏ธ useState ์™€ useAtom์˜ ์ฐจ์ด์ 

const [count, setCount] = useState(0); 

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

useState๋Š” ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ์—์„œ๋งŒ ์“ฐ์ง€๋งŒ,
useAtom์€ ์ „์—ญ์ฒ˜๋Ÿผ ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ์—์„œ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ” ํŒŒ์ƒ Atom (Derived Atom)

ํ•˜๋‚˜์˜ atom์„ ๊ธฐ์ค€์œผ๋กœ ์ƒˆ๋กœ์šด atom์„ ๋งŒ๋“ค๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.
๊ณ„์‚ฐ๋œ ๊ฐ’์ด๋‚˜ ๊ฐ€๊ณต๋œ ๊ฐ’์„ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.
get()์„ ํ†ตํ•ด ๋‹ค๋ฅธ atom์˜ ๊ฐ’์„ ๋ถˆ๋Ÿฌ์˜จ๋‹ค.

const countAtom = atom(1); // ๊ธฐ๋ณธ ์ˆซ์ž ์ƒํƒœ
const doubleAtom = atom((get) => get(countAtom) * 2); // 

๐Ÿ‘‰ doubleAtom์€ countAtom์˜ ๊ฐ’์„ ๊ฐ์‹œํ•œ๋‹ค.

๐Ÿ‘‰ ๋งŒ์•ฝ countAtom์ด 3์ด ๋˜๋ฉด, doubleAtom์€ ์ž๋™์œผ๋กœ 6์ด ๋œ๋‹ค.

๐Ÿ‘‰ doubleAtom์€ ์ฝ๊ธฐ ์ „์šฉ์ด๊ธฐ ๋•Œ๋ฌธ์—, ์ƒํƒœ๋ฅผ ์ง์ ‘ ์ˆ˜์ •ํ•  ์ˆ˜๋Š” ์—†๋‹ค.

๋งŒ์•ฝ ์“ฐ๊ธฐ ์ „์šฉ์„ ๋งŒ๋“ค๊ณ  ์‹ถ๋‹ค๋ฉด?

๐Ÿงฐ ์“ฐ๊ธฐ ๊ฐ€๋Šฅํ•œ ํŒŒ์ƒ Atom

doubleAtom์€ ์ฝ๊ธฐ ์ „์šฉ์ด์ง€๋งŒ, ์ฝ๊ธฐ์™€ ์“ฐ๊ธฐ๋ฅผ ๋ชจ๋‘ ์ง€์›ํ•˜๊ณ  ์‹ถ์„ ๋•Œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ๋œ๋‹ค.

const countAtom = atom(0);

const countControlAtom = atom(
  (get) => get(countAtom), // ์ฝ๊ธฐ
  (get, set, newValue) => set(countAtom, newValue) // ์“ฐ๊ธฐ
);

get: ํ˜„์žฌ ์ƒํƒœ๋ฅผ ์ฝ์„ ๋•Œ ์‚ฌ์šฉ

set: ๋‹ค๋ฅธ atom์˜ ๊ฐ’์„ ์ˆ˜์ •ํ•  ๋•Œ ์‚ฌ์šฉ -> ์“ฐ๊ธฐ ์ „์šฉ ๊ตฌํ˜„ ๊ฐ€๋Šฅ!

newValue: ์™ธ๋ถ€์—์„œ ์ด atom์— ์ „๋‹ฌํ•œ ์ƒˆ ๊ฐ’

๐Ÿ‘‰ ์ด๋กœ์จ, atom ๊ฐ’์„ ์™ธ๋ถ€์—์„œ ์ง์ ‘ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

โณ ๋น„๋™๊ธฐ Atom

atom(async () => {...}) ํ˜•ํƒœ๋กœ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.
๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ฑฐ๋‚˜, ์„œ๋ฒ„ ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ ์œ ์šฉํ•˜๋‹ค. ์ฆ‰, useEffect ์—†์ด๋„ ๋น„๋™๊ธฐ ์ƒํƒœ๋ฅผ ์•„์ฃผ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

const userAtom = atom(async () => {
  const res = await fetch('https://jsonplaceholder.typicode.com/users/1');
  return await res.json();
});
const [user] = useAtom(userAtom);

return <div>{user.name}</div>;

userAtom์€ API ์‘๋‹ต์„ ์ž๋™์œผ๋กœ ๋ฐ›์•„์˜ค๊ธฐ ๋•Œ๋ฌธ์—,
useAtom(userAtom)์œผ๋กœ ํ˜ธ์ถœ๋งŒ ํ•ด๋„ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

๋กœ๋”ฉ, ์—๋Ÿฌ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ  ์‹ถ์œผ๋ฉด Suspense๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ, ํ•„์š”์— ๋”ฐ๋ผ ๋ณ„๋„๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

์ตœ์ข…์ •๋ฆฌ

ํ•ญ๋ชฉ์„ค๋ช…
๋‹จ์ˆœํ•œ ๋ฌธ๋ฒ•useState์ฒ˜๋Ÿผ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
์ „์—ญ ์ƒํƒœ ๊ณต์œ ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ์—์„œ atom ๊ณต์œ 
๊ณ„์‚ฐ๋œ ์ƒํƒœํŒŒ์ƒ atom์œผ๋กœ ๊ฐ’ ์ž๋™ ๊ณ„์‚ฐ
๋น„๋™๊ธฐ ์ž‘์—… ์ง€์›API ์š”์ฒญ๋„ atom์œผ๋กœ ์ฒ˜๋ฆฌ
์ตœ์†Œ ๋ Œ๋”๋ง ๋‹จ์œ„ํ•„์š”ํ•œ ์ปดํฌ๋„ŒํŠธ๋งŒ ๋ฆฌ๋ Œ๋”๋ง๋จ

โœ๏ธ ๋ฐฐ์šด์ 

ํ”„๋กœ์ ํŠธ ๋ฏธ์…˜์„ ํ†ตํ•ด Jotai๋ผ๋Š” ์ƒˆ๋กœ์šด ์ƒํƒœ๊ด€๋ฆฌ ๋„๊ตฌ๋ฅผ ์ ‘ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค. ์ฒ˜์Œ์—” "useState(useState๋ฅผ ๋ชจ๋ฅธ๋‹ค๋ฉด?: https://velog.io/@krsjkim/React-์‚ผํ˜•์ œ-Hook-useState-useEffect-useNavigate ์ฐธ๊ณ ) ๋ž‘ ๋ญ๊ฐ€ ๋‹ค๋ฅด์ง€?"๋ผ๋Š” ์˜๋ฌธ์ด ๋“ค์—ˆ์ง€๋งŒ, ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•ด๋ณด๋ฉด์„œ Jotai์˜ ์ „์—ญ ์ƒํƒœ ๊ณต์œ ์˜ ๊ฐ„ํŽธํ•จ, ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ atom ๊ตฌ์กฐ, ๊ทธ๋ฆฌ๊ณ  ๋ถˆํ•„์š”ํ•œ ๋ Œ๋”๋ง์„ ์ค„์—ฌ์ฃผ๋Š” ์„ค๊ณ„ ๋ฐฉ์‹์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์„ ๋ฐฐ์› ๊ณ , ์ด ๋‚ด์šฉ์„ ์ •๋ฆฌํ•ด๋ณด๊ณ  ์‹ถ๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์–ด ์ด๋ฒˆ ์œ„ํด๋ฆฌ ๋ธ”๋กœ๊ทธ ์ฃผ์ œ๋กœ ์ž‘์„ฑํ•ด๋ณด์•˜๋‹ค.

๐Ÿ“ฆ ์ƒํƒœ๊ด€๋ฆฌ ๋„๊ตฌ๋“ค ๊ฐ„๋‹จ ๋น„๊ต
Redux ๐Ÿ‘‰ ํšŒ์‚ฌ์šฉ, ๋ณต์žกํ•จ
Recoil ๐Ÿ‘‰ ์‹คํ—˜์ , ์–ด๋ ต์ง€๋งŒ ์œ ์—ฐํ•จ
Zustand ๐Ÿ‘‰ ํŽธํ•˜์ง€๋งŒ ๊ตฌ์กฐ ์žก๊ธฐ ํ•„์š”
Jotai ๐Ÿ‘‰ ์‹ฌํ”Œํ•˜๊ณ  ๊ฐ€๋ณ๋‹ค!

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

6๊ฐœ์˜ ๋Œ“๊ธ€

comment-user-thumbnail
2025๋…„ 6์›” 18์ผ

์ „์—ญ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ค‘์—์„œ ๊ฐ€์žฅ ํŽธํ•˜๊ฒŒ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋Š”๊ฒŒ jotai์ด๋‹ค ๋ณด๋‹ˆ ๋จผ์ € ๊ฐ€์ ธ์˜ค๊ฒŒ ๋˜์—‡์–ด์š” ๋ฌผ๋ก  ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค๋„ ์žฅ๋‹จ์ ์ด ์žˆ๊ธดํ•˜๊ฒ ์ง€๋งŒ ์ง€๊ธˆ์€ ์šฐ์„  '์ „์—ญ ์ƒํƒœ์˜ ๊ด€๋ฆฌ๊ฐ€ ์™œ ํ•„์š”ํ•œ์ง€'์— ๋Œ€ํ•ด์„œ ์ดˆ์  ๋งž์ถฐ์„œ ์ดํ•ด๋ฅผ ํ•˜๊ณ  ๋‚˜์„œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์„ ์จ๋ณด๋Š”๊ฒŒ ์ข‹์€๊ฑฐ ๊ฐ™์•„์šฉ

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ
comment-user-thumbnail
2025๋…„ 6์›” 20์ผ

jotai๋Š” ๊ฐ„๊ฒฐํ•ด์„œ ๋„ˆ๋ฌด ํŽธํ•œ ๊ฒƒ ๊ฐ™์•„์š”. ๋ฌผ๋ก  zustand๋„ ์ข‹์Šต๋‹ˆ๋‹ค!

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ
comment-user-thumbnail
2025๋…„ 6์›” 23์ผ

๋‚œ์ƒ ์ฒ˜ ์Œ ๋“ค ์–ด ๋ด ......
์ด๋Ÿฐ ๊ฒƒ๋„ ์žˆ๊ตฐ์š” ๊ฐ™์ด ํ”Œ์ ํŠธ๋ž™ ํ•œ ๊ฒŒ ๋งž์„๊นŒ์š”? ์–ด์ฐŒ๋๋“  ์ข‹์€ ๊ธ€ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค .......

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ
comment-user-thumbnail
2025๋…„ 6์›” 28์ผ

Jotai๋ผ๋Š”๊ฑธ ์ฒ˜์Œ ์•Œ๊ฒŒ๋์–ด์š”. useState๋งŒ ์‚ฌ์šฉํ•ด ๋ดค๋Š”๋ฐ ๋น„์Šทํ•˜๋ฉด์„œ๋„ ๋” ๊ฐ„ํŽธํ•˜๊ตฐ์š”. ๋‚˜์ค‘์— ํ•œ๋ฒˆ ์จ๋ด์•ผ๊ฒ ์–ด์š”

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ
comment-user-thumbnail
2025๋…„ 6์›” 29์ผ

๋น„์Šทํ•œ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•ด์•ผ ํ–ˆ๋Š”๋ฐ ์ด๋ฒˆ์—๋Š” useState๋ง๊ณ  jotai๋ฅผ ์‚ฌ์šฉํ•ด๋ด๋„ ์ข‹์„ ๊ฒƒ ๊ฐ™์•„์š”!

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ
comment-user-thumbnail
2025๋…„ 6์›” 30์ผ

ํ•œ๋ฒˆ๋„ ์•ˆ์จ๋ดค๋Š”๋ฐ ์‚ฌ์šฉํ•ด๋ณด๊ณ  ์‹ถ๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ๋Š” ๊ธ€์ด๋„ค์šฉ

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ