๐ย ๋ถ์์ ์์
์ด ํฌ์คํธ๋ ์ํ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ Jotai V2๋ฅผ ๊ธฐ์ค์ผ๋ก ์์ฑ๋์์ต๋๋ค.
ํ์ฌ ์งํ์ค์ธ ํ๋ก์ ํธ์ย Jotai
๋ฅผ ์ฌ์ฉํด ์ ์ญ์ํ๋ฅผ ๊ด๋ฆฌํ๊ณ ์์ต๋๋ค.
๊ทธ ๊ณผ์ ์์ ์๋์ ๊ฐ์ ๋ช ๊ฐ์ง ๊ถ๊ธ์ ์ด ์๊ฒผ์ต๋๋ค.
- ์ด๋ป๊ฒย
Root
๋ฅผ ๊ฐ์ธ๋ยProvider
ย ์์ด ๊ฐ ์ปดํฌ๋ํธ์์ ๋์ผํ ์ํ๋ฅผ ๊ตฌ๋ ํ ์ ์์ง? Provider
๋ฅผ ๊ฐ์ธ๊ฒ ๋ ๊ฒฝ์ฐ, ๊ฐ์ฅ ๊ฐ๊น์ดยProvider
์ ์ํ๋ฅผ ๊ฐ์ ธ์ค๊ฒ ๋๋๋ฐ ์ด๋ค ๋ฐฉ์์ผ๋ก ๋์ํ๋ ๊ฑธ๊น?Provider
๊ฐ ์์ ๋, ๊ฐ์ยupdate
ย ํ ๊ฒฝ์ฐ, ์ด๋ค ๋ก์ง์ผ๋กยrerendering
์ด ์ด๋ฃจ์ด์ง๊น?
๊ถ๊ธ์ค์ ํด๊ฒฐํ ๊ฒธ ์ํ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌย Jotai
์ ๋์์๋ฆฌ๋ฅผ ๋ถ์ํ๊ฒ ๋์์ต๋๋ค.
์ด์ ์,ย Redux
์ ๋์์๋ฆฌ๋ฅผ ์ดํด๋ณธ ๊ฒฝํ์ด ์์์ต๋๋ค.
Redux
์ ๊ฒฝ์ฐ์๋ย Vanila JavaScript
์์๋ ์ฌ์ฉ ๊ฐ๋ฅํ ์คํ ์ด ๊ตฌํ๋ถ(Pub-Sub
ย ํจํด ์ฌ์ฉ)๊ฐ ์์๊ณ ,ย React
์์ ์ฌ์ฉ ๊ฐ๋ฅํ๋๋ก ํ๋ฒ Wrapping์ ํด์ย React
์์ ์ฌ์ฉ ๊ฐ๋ฅํ๋๋ก(React-Redux
) ๋ง๋๋ ํํ์์ต๋๋ค.
Jotai
ย ๋ย React
ย ์ ์ฉ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด์ง๋ง,ย Atom
๊ณผ ์ด๋ฅผ ์ ์ฅํ๋ย Store
์ ๊ฒฝ์ฐย Vanila JavaScript
๋ฅผ ์ด์ฉํด ๊ตฌํ๋์ด ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ด๋ฅผ ์ฌ์ฉํ๋ย Hook(useAtom, useSetAtom โฆ)
์ ๊ฒฝ์ฐย React
์์ ์ ๊ณตํ๋ย Hook
์ ์ด์ฉํด ๊ตฌํ๋์ด ์์ต๋๋ค. ์ด์ ๋ฐ๋ผ,ย Vanila JavaScript
๋ฅผ ์ด์ฉํด ๊ตฌํ๋ย Atom
์ ๋จผ์ ์ดํด๋ณด๊ณ , ์ด๋ฅผ ์ฌ์ฉํ๋ ํ
์ ์ฐจ๋ก๋๋ก ์ดํด๋ณด๊ฒ ์ต๋๋ค.
Jotai
โโ vanila
โโ react
Jotai
โโ vanila
โโ react
โ๏ธย Atom
๊ณต์๋ฌธ์์์๋ย Atom
์ ๋ค์๊ณผ ๊ฐ์ด ์ค๋ช
ํฉ๋๋ค.
The atom function is to create an atom config. We call it "atom config" as it's just a definition and it doesn't yet hold a value. We may also call it just "atom" if the context is clear.
Atom
ย ํจ์๋ฅผ ์ฌ์ฉํดย Atom Config
๋ฅผ ์์ฑํ๋ค.
Jotai
์์ ์ ์ํย Atom
์ ๊ทธ ์์ฒด๋ก ๊ฐ์ ๊ฐ์ง์ง ์์ผ๋ฉฐ,ย Atom
์ ํตํดย Store
์ ์ ๊ทผํด, ๊ฐ์ ๊ฐ์ ธ์ต๋๋ค(read)
๊ณต์๋ฌธ์์ ๋์์๋ ๋ฐ์ ๋ฐ๋ฅด๋ฉด,ย Atom
์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ์ด 4๊ฐ์ง์
๋๋ค. (primitive, ์ฝ๊ธฐ์ ์ฉ, ์ฐ๊ธฐ์ ์ฉ, ์ฝ๊ธฐ and ์ฐ๊ธฐ)
import { atom } from "jotai";
const primitiveAtom = atom(10);
const readOnlyAtom = atom((get) => get(priceAtom) * 2);
const writeOnlyAtom = atom(null, (get, set, update) => {
set(priceAtom, get(priceAtom) - update.discount);
});
const readWriteAtom = atom(
(get) => get(priceAtom) * 2,
(get, set, newPrice) => {
set(priceAtom, newPrice / 2);
}
);
import { atom } from "jotai";
const primitiveAtom = atom(10);
const readOnlyAtom = atom((get) => get(priceAtom) * 2);
const writeOnlyAtom = atom(null, (get, set, update) => {
set(priceAtom, get(priceAtom) - update.discount);
});
const readWriteAtom = atom(
(get) => get(priceAtom) * 2,
(get, set, newPrice) => {
set(priceAtom, newPrice / 2);
}
);
atom
์ ๊ตฌํ๋ถ๋ ์๋์ ๊ฐ์ต๋๋ค.
export function atom<Value, Args extends unknown[], Result>(
read: Value | Read<Value, SetAtom<Args, Result>>,
write?: Write<Args, Result>
) {
const key = `atom${++keyCount}`const config = {
toString: () => key,
} as WritableAtom<Value, Args, Result> & { init?: Value }
if (typeof read === 'function') {
config.read = read as Read<Value, SetAtom<Args, Result>>
} else {
config.init = read
config.read = (get) => get(config)
config.write = ((get: Getter, set: Setter, arg: SetStateAction<Value>) =>set(
config as unknown as PrimitiveAtom<Value>,
typeof arg === 'function'
? (arg as (prev: Value) => Value)(get(config))
: arg
)) as unknown as Write<Args, Result>
}
if (write) {
config.write = write
}
return config
}
export function atom<Value, Args extends unknown[], Result>(
read: Value | Read<Value, SetAtom<Args, Result>>,
write?: Write<Args, Result>
) {
const key = `atom${++keyCount}`const config = {
toString: () => key,
} as WritableAtom<Value, Args, Result> & { init?: Value }
if (typeof read === 'function') {
config.read = read as Read<Value, SetAtom<Args, Result>>
} else {
config.init = read
config.read = (get) => get(config)
config.write = ((get: Getter, set: Setter, arg: SetStateAction<Value>) =>set(
config as unknown as PrimitiveAtom<Value>,
typeof arg === 'function'
? (arg as (prev: Value) => Value)(get(config))
: arg
)) as unknown as Write<Args, Result>
}
if (write) {
config.write = write
}
return config
}
์ด์ ์ ๊ณต์๋ฌธ์์ ๋์ ์๋ ์ค๋ช
๋๋ก,ย atom
ย ์์ฒด๋ ์ํ๋ฅผ ์ ์ฅํ์ง ์์ต๋๋ค.
์ ์ฅํ์ง ์๊ณ ,ย init
,ย read
,ย write
,ย toString
ย ๋ฉ์๋๋ฅผ ๊ฐ์ง๋ย config
๋ฅผ ๋ง๋ค์ด ๋ฐํํ ๋ฟ์
๋๋ค.
๊ทธ๋ฆฌ๊ณ ,ย Store
์ ์ ์ฅ๋๋ ๊ฐ๊ฐ์ย atom
์ด ์ ๋ํฌํย key
๋ฅผ ๊ฐ์ง๊ธฐ ์ํด ๋ณ์ย keyCount
๋ฅผ ์ฌ์ฉํ๊ณ ์์ต๋๋ค.
๊ฐ์ ์ฝ๊ณ ์ฐ๋๋ฐ ์ฌ์ฉ๋๋ย read
์ย write
ย ๋ฉ์๋๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
๋จผ์ ย read
์
๋๋ค.
๊ณต์๋ฌธ์์ย read
์ ๋ํด ์๋์ ๊ฐ์ ์ค๋ช
์ด ์์ต๋๋ค.
read: a function that's called on every re-render. The signature of read is (get) => Value | Promise(Value), and get is a function that takes an atom config and returns its value stored in Provider as described below. Dependency is tracked, so if get is used for an atom at least once, the read will be reevaluated whenever the atom value is changed.
๊ณต์๋ฌธ์์ ๋ด์ฉ์ ํตํด,ย read
๋ย get
์ด๋ผ๋ ํจ์๋ฅผ ๋งค๊ฒ๋ณ์๋ก ๋ฐ๋๋ฐ, ํด๋นย get
ย ํจ์๋ย atom config
์ ๋งค๊ฒ๋ณ์๋ก ๋ฐ์,ย Store
์ ์ ์ฅ๋์ด ์๋ ๊ฐ(value)๋ฅผ ๊ฐ์ ธ์จ๋ค๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
์ถ๊ฐ๋กย read
์ ํ์
(Read
)์ ํตํด์๋,ย read
๊ฐย Store
์ ์ ์ฅ๋์ด ์๋ ๊ฐ(value)๋ฅผ ๊ฐ์ ธ์จ๋ค๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
type Read<Value, SetSelf = never> = (
get: Getter,
options: { readonly signal: AbortSignal; readonly setSelf: SetSelf }
) => Value;
type Getter = <Value>(atom: Atom<Value>) => Value;
type Read<Value, SetSelf = never> = (
get: Getter,
options: { readonly signal: AbortSignal; readonly setSelf: SetSelf }
) => Value;
type Getter = <Value>(atom: Atom<Value>) => Value;
Atom
์ ๊ฐ์ ์ฐ๊ธฐ ์ํด ์ฌ์ฉ๋๋ย write
์ ๊ฒฝ์ฐ์๋ ์๋์ ๊ฐ์ ๊ตฌํ๋ถ๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค.
config.write = ((get: Getter, set: Setter, arg: SetStateAction<Value>) =>
set(
config as unknown as PrimitiveAtom<Value>,
typeof arg === "function"
? (arg as (prev: Value) => Value)(get(config))
: arg
)) as unknown as Write<Args, Result>;
config.write = ((get: Getter, set: Setter, arg: SetStateAction<Value>) =>
set(
config as unknown as PrimitiveAtom<Value>,
typeof arg === "function"
? (arg as (prev: Value) => Value)(get(config))
: arg
)) as unknown as Write<Args, Result>;
์ฒซ ๋ฒ์งธ ๋งค๊ฒ๋ณ์๋ก ์์์ ํ์ธํ๋ย Store
์์ย Atom
์ ๊ฐ(Value)์ ๊ฐ์ ธ์ฌ ์ ์๋ย get
์ ์ ๋ฌํ๊ณ , ๋ ๋ฒ์งธ ๋งค๊ฒ๋ณ์๋กย Atom
์ ๊ฐ์ ์ฐ๋ ํจ์๋ก ์์๋๋ย set
์ ์ ๋ฌํ๋ฉฐ, ๋ง์ง๋ง์ผ๋ก ํน์ ๋์ ํน์ ์ธํ
ํ๋ ค๋ ๊ฐ์ ์ํ ๊ฒ์ผ๋ก ์์๋๋ย arg
๋ฅผ ๋ฐ๋ ๊ฒ์ ํ์ธ ํ ์ ์์ต๋๋ค.
์ง๊ธ๊น์ง์ ๊ตฌ์กฐ๋ฅผ ๊ทธ๋ฆผ์ผ๋ก ๋ํ๋ด๋ฉด ์๋์ ๊ฐ์ต๋๋ค.ย Store
์ ์ฌ๋ฌ ๊ฐ์ย atom
์ด ์ ์ฅ๋์ด ์๋ ํํ์ด๋ฉฐ, ์ธ๋ถ์์ย atom
์ ๊ฐ์ ์ฝ๊ฑฐ๋ ์ด๋ค๋ฉด,ย Store(Provider)
์ ์กด์ฌํ๋ย atom
์ read, writeํ๋ ๊ตฌ์กฐ์
๋๋ค.
๐ ย Provider
์ด๋ฒ์๋ ๊ฐ์ ์ฝ์ด์ค๋ย Store
์ ์ญํ ์ ํ๋ย Provider
์ ๋ํด ์์๋ณด๊ฒ ์ต๋๋ค.
๋จผ์ ๊ณต์๋ฌธ์์ ์ค๋ช ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
Provider
์ ๋ํ ์ค๋ช
์
๋๋ค.
The Provider component is to provide state for a component sub tree. Multiple Providers can be used for multiple subtrees, and they can even be nested. This works just like React Context. If an atom is used in a tree without a Provider, it will use the default state. This is so-called provider-less mode.
Provider
๋ย Component Subtree
๋ฅผ ์ํ ์ปดํฌ๋ํธ์ด๋ฉฐ,ย React Context
์ ๋น์ทํ๊ฒ ๋์ํ๋ค. ๊ทธ๋ฆฌ๊ณ ย Provider
๊ฐ ์๋ค๋ฉด,ย default state
๋ฅผ ์ฌ์ฉํ๋คโ ๋ผ๊ณ ๋์์์ต๋๋ค.
Provider
์ ์์ค์ฝ๋๋ฅผ ์๋์ ๊ฐ์ต๋๋ค
const StoreContext = createContext<Store | undefined>(undefined);
export const Provider = ({
children,
store,
}: {
children?: ReactNode;
store?: Store;
}): FunctionComponentElement<{ value: Store | undefined }> => {
const storeRef = useRef<Store>();
if (!store && !storeRef.current) {
storeRef.current = createStore();
}
return createElement(
StoreContext.Provider,
{
value: store || storeRef.current,
},
children
);
};
const StoreContext = createContext<Store | undefined>(undefined);
export const Provider = ({
children,
store,
}: {
children?: ReactNode;
store?: Store;
}): FunctionComponentElement<{ value: Store | undefined }> => {
const storeRef = useRef<Store>();
if (!store && !storeRef.current) {
storeRef.current = createStore();
}
return createElement(
StoreContext.Provider,
{
value: store || storeRef.current,
},
children
);
};
์์ค์ฝ๋๋ฅผ ํตํด ๊ฐ๊ฐ์ย Provider
๋ย createContext
๋ฅผ ํตํด ๋ง๋ค์ด์ง, ๋
์์ ์ธย Reactย Context
๋ผ๋ ์ฌ์ค์ ์ ์ ์์ต๋๋ค.
๋ํ,ย Store
๋ฅผย Prop
์ผ๋ก ๋ฐ์, ํด๋นย Subtree
์์ ์ฌ์ฉํ ย store
๋ฅผ ์ง์ ํ ์ ์์ผ๋ฉฐ,ย store
๋ผ๋ ๋งค๊ฒ๋ณ์๋ย Optional
ย ํ๊ธฐ ๋๋ฌธ์, store๊ฐ ์กด์ฌํ์ง ์์ ๊ฒฝ์ฐ,ย createStore
๋ฅผ ํตํดย Store
๋ฅผ ๋ง๋ค์ดย Provider
์ ์ ์ฅํ๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
๊ณต์๋ฌธ์์ ์ค๋ช
์์๋ โย Provider
๊ฐ ์๋ค๋ฉด,ย default state
๋ฅผ ์ฌ์ฉํ๋คโ ๋ผ๊ณ ๋์ ์๋๋ฐ, ์ด๋ ์๋๋ฅผ ํตํด์ ํ์ธํ ์ ์์ต๋๋ค.
๊ธฐ๋ณธ ํ๋ฆ์ ์๋์ ๊ฐ์ต๋๋ค.
Jotai
์ ๊ธฐ๋ณธ ๋์์ด ๋๋ Hook์ธยuseAtomValue
,ยuseSetAtom
์ยStore
๋ฅผ ๋ฐํํ๋ยuseStore
ย Hook์ ํตํด, ํ์ฌ ์ปดํฌ๋ํธ๊ฐ ํฌํจ๋์ด ์๋ยProvider
์ ๋งค์นญ๋ยStore
๋ฅผ ๊ฐ์ ธ์ค๊ฒ ๋ฉ๋๋ค.- ์ด ๊ณผ์ ์์ย
useStore
ย Hook์ ํด๋น ํธ๋ฆฌ๋ฅผ ๋ฐ๋ผ ํ์ํ๊ณ ์ปดํฌ๋ํธ๊ฐ ํฌํจ๋์ด ์๋ยProvider
๊ฐ ์๋ค๋ฉด,ยgetDefaultStore
ย ํจ์๋ฅผ ํตํดยdefaultStore
๋ฅผ ๋ฐํํ๊ฒ ๋ฉ๋๋ค.
์์ค์ฝ๋๋ ์๋์ ๊ฐ์ต๋๋ค.
export function useAtomValue<Value>(atom: Atom<Value>, options?: Options) {
const store = useStore(options);
// get value from store
// ...
return isPromiseLike(value) ? use(value) : (value as Awaited<Value>);
}
export function useSetAtom<Value, Args extends any[], Result>(
atom: WritableAtom<Value, Args, Result>,
options?: Options
) {
const store = useStore(options);
// set value in store
const setAtom = useCallback(
(...args: Args) => {
// ...
return store.set(atom, ...args);
},
[store, atom]
);
return setAtom;
}
export const useStore = (options?: Options): Store => {
const store = useContext(StoreContext);
return options?.store || store || getDefaultStore();
};
export function useAtomValue<Value>(atom: Atom<Value>, options?: Options) {
const store = useStore(options);
// get value from store
// ...
return isPromiseLike(value) ? use(value) : (value as Awaited<Value>);
}
export function useSetAtom<Value, Args extends any[], Result>(
atom: WritableAtom<Value, Args, Result>,
options?: Options
) {
const store = useStore(options);
// set value in store
const setAtom = useCallback(
(...args: Args) => {
// ...
return store.set(atom, ...args);
},
[store, atom]
);
return setAtom;
}
export const useStore = (options?: Options): Store => {
const store = useContext(StoreContext);
return options?.store || store || getDefaultStore();
};
๊ทธ๋ ๋ค๋ฉด, ์๋ก ๋ค๋ฅธย Subtree(Provider)
์์, ๊ฐ์ย store
๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ์ด๋ค ์ํฉ์ด ๋ฒ์ด์ง๊น์?
Counter ์์ ์์ค์ฝ๋
const counter1Atom = atom(0);
const counter2Atom = atom(10);
const store1 = createStore();
const store2 = createStore();
function App() {
return (
<div className="App">
<Provider store={store1}>
<ComponentA />
</Provider>
<Provider store={store2}>
<ComponentB />
</Provider>
</div>
);
}
const ComponentA = () => {
const [count, setCount] = useAtom(counter1Atom);
const count2 = useAtomValue(counter2Atom);
console.log("count2 : ", count2);
return <Counter count={count} setCount={setCount} />;
};
const ComponentB = () => {
const [count, setCount] = useAtom(counter2Atom);
return <Counter count={count} setCount={setCount} />;
};
const Counter = ({ count, setCount }: CounterProps) => {
return (
<>
<button onClick={() => setCount((prev: any) => prev - 1)}>-</button>
<span>{count}</span>
<button onClick={() => setCount((prev: any) => prev + 1)}>+</button>
</>
);
};
const counter1Atom = atom(0);
const counter2Atom = atom(10);
const store1 = createStore();
const store2 = createStore();
function App() {
return (
<div className="App">
<Provider store={store1}>
<ComponentA />
</Provider>
<Provider store={store2}>
<ComponentB />
</Provider>
</div>
);
}
const ComponentA = () => {
const [count, setCount] = useAtom(counter1Atom);
const count2 = useAtomValue(counter2Atom);
console.log("count2 : ", count2);
return <Counter count={count} setCount={setCount} />;
};
const ComponentB = () => {
const [count, setCount] = useAtom(counter2Atom);
return <Counter count={count} setCount={setCount} />;
};
const Counter = ({ count, setCount }: CounterProps) => {
return (
<>
<button onClick={() => setCount((prev: any) => prev - 1)}>-</button>
<span>{count}</span>
<button onClick={() => setCount((prev: any) => prev + 1)}>+</button>
</>
);
};
์๋ก ๋ค๋ฅธย Subtree
์์ ๋ค๋ฅธย Store
๋ฅผ ์ฌ์ฉํ๊ฒ ๋ ๊ฒฝ์ฐ, ๋ค๋ฅธย Subtree
์์ ๊ฐฑ์ ๋ ๊ฐ์ ์ฝ์ด ์ฌ ์ ์์ต๋๋ค.
๋ฐ๋ฉด, ์๋ก ๋ค๋ฅธย Subtree
์์ ๊ฐ์ย store
๋ฅผ ์ฌ์ฉํ๊ฒ ๋ ๊ฒฝ์ฐ, ๋ค๋ฅธย Subtree(Provider)
์ผ์ง๋ผ๋ ์
๋ฐ์ดํธ ๋ ๊ฐ์ ์ฝ์ด ์ฌ์ ์์ต๋๋ค.
<Provider store={store1}>
<ComponentA />
</Provider>
<Provider store={store1}>
<ComponentB />
</Provider>
<Provider store={store1}>
<ComponentA />
</Provider>
<Provider store={store1}>
<ComponentB />
</Provider>
์ถ๊ฐ์ ์ผ๋ก, ๋ค๋ฅธย Store
๋ฅผ ์ฌ์ฉํ ๋์ ๋ค๋ฅด๊ฒ,ย counter2Atom
์ ๊ฐ์ด ์
๋ฐ์ดํธ ๋๋ฉด,ย ComponentA
๊ฐ ๋ฆฌ๋ ๋๋ง ๋์ด ์ฝ์์ด ์ถ๋ ฅ๋๋๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
์ด๋ฅผ ํตํด,ย Provider(Context)
๋ ๊ป๋ฐ๊ธฐ์ด๋ฉฐ, ๊ฐ์ ๊ฐ์ ธ์ค๊ณ ์
๋ฐ์ดํธํ๋ฉฐ ์ปดํฌ๋ํธ๋ฅผ ๋ฆฌ๋ ๋๋ง ์ํค๋ ๋ก์ง์ย Store
์ ๋ค์ด์๋ค๋ ์ฌ์ค์ ์ ์ ์์ต๋๋ค.
๐ ๋ง์น๋ฉฐ
1ํธ์์๋ ๊ฐ์ฅ ๊ธฐ๋ณธ์ด ๋๋ย atom
๊ณผย store
์ ๊ป๋ฐ๊ธฐ๊ฐ ๋๋ย Provider
์ ๋ํด์ ์์๋ณด์์ต๋๋ค.
์ง๊ธ๊น์ง ํ์ ํ ๋ด์ฉ์ ์์ฝํ๋ฉด ์๋์ ๊ฐ์ต๋๋ค.
atom
์ ๊ทธ ์์ฒด๋ก ๊ฐ์ ๊ฐ์ง์ง ์๊ณ ยStore
์ ์ ์ฅ๋๋ฉฐ, ๋ชจ๋ ๋์์ยstore
์์ ๊ฐ์ ์ฝ๊ณ ์ฐ๋ ๊ณผ์ ์ ํตํด ์ด๋ฃจ์ด์ง๋ค.Provider
๋ยStore
๋ฅผ ์ ์ฅํ๋ ๊ป๋ฐ๊ธฐ ์ญํ ์ ํ๋ฉฐ,ยProvider
๊ฐ ์์ ๊ฒฝ์ฐ,ยdefaultStore
๋ฅผ ์ฌ์ฉํ๋ค.
๋ค์ 2ํธ์์๋ ์๋์ ๊ฐ์ ๋ด์ฉ์ ์ดํด๋ณผ ์์ ์ ๋๋ค.
Jotai
์ ํต์ฌ ๋ก์งยStore
atom
์ด ๋ณ๊ฒฝ๋์์ ๋, ์ปดํฌ๋ํธ๋ ์ด๋ป๊ฒ ๋ฆฌ๋ ๋๋ง ๋๋๊ฐatom
์ ์ด๋ค ์์ ์ยstore
์ ๋ค์ด๊ฐ๋๊ฐ- ๊ฐย
atom
์ยdependency
๋ฅผ ์ด๋ป๊ฒ ๊ด๋ฆฌ๋๋๊ฐ