跳至主要内容

[note] jotai 筆記

TL;DR

import { atom, useAtom, useAtomValue } from 'jotai';
import { useAtomValue, useUpdateAtom } from 'jotai/utils'

const isEditingAtom = atom(false);

const App = () => {
// normal usage
const [isEditing, setIsEditing] = useAtom(countAtom)

// if only need the setter
// useUpdateAtom can prevent unnecessary re-render
const setIsEditing = useUpdateAtom(isEditingAtom);

// if only need the getter
const isEditing = useAtomValue(isEditingAtom);
}

MISC

Resettable

resettable @ jotai > guides

使用 atomWithResetuseResetAtom 可以把取得一個 function 來把 atom 設回 default value:

const todoListAtom = atomWithReset([{ description: 'Add a todo', checked: false }])

const TodoList = () => {
const [todoList, setTodoList] = useAtom(todoListAtom)
const resetTodoList = useResetAtom(todoListAtom)

return <button onClick={resetTodoList}>Reset</button>;
}

Good Discussion

如果想要在 render 時不透過 useEffect 設定 atom 的初始值

Can an atom be initialized on the first render? @ Github Discussion

// https://github.com/pmndrs/jotai/discussions/581#discussioncomment-972361

const fooAtom = atom(null)

const ParentComponent = ({ foo }) => (
<Provider initialValues={[[fooAtom, foo]]}>
<ChildComponent />
</Provider>
)

const ChildComponent = () => {
const [foo, setFoo] = useAtom(fooAtom)
// foo is already initialized.
}

Provider and share atom

How to share atom between Provider and custom hook

Jotai 本身也提供了類似 React Context 中 Provider 概念的 <Provider />,所有在該 Provider 中使用到的 atom,都會隸屬在這個 Provider 底下(如果沒有用 Provider 的話,預設 atom 都是 global 的),atom 會往上找到最近一個的 <Provider />

如果有些 atom 想要在不同 Providers 間被共用的話,因為預設這個 atom 的狀態會被限縮在該 Provider 底下,導致無法被共用,這時候我們可以建立一個更高層的 Provider,並且搭配 scope 來達到。

舉例來說,如果希望在 Next.js 中建立能在 "Global Atom" 而不會被各自 modules 內的 <Provider /> 給影響,可以這麼做(sample code):

_app.ts 加入 scope=global 的 Provider

// _app.ts
<Provider scope="global">
{/* ... */}
</Provider>

接著即使 Module 內有再使用 Provider,也可以透過 scope 找到 global 的 Provider 來取用資料(jotai 會往上找到最靠近且 scope 名稱一樣的 Provider):

const [isEditing, setIsEditing] = useAtom(isEditingAtom, 'global');