跳转到内容

Debugging

在简单的应用中,console.log 可能是调试原子最好的工具。但当应用变得更大、需要使用更多原子时,日志打印就不再是调试原子的好方式了。 Jotai 提供了两种调试原子的方式:React Dev ToolsRedux Dev Tools。如果只是读取值和简单调试,React Dev Tools 可能就够了;但对于时间旅行和设置值等更复杂的任务,Redux Dev Tools 会是更好的选择。

值得一提的是,Jotai 中有一个叫做调试标签的概念,它可以帮助我们调试。 默认情况下,每个 Jotai 状态的标签类似于 1:<no debugLabel>,其中的数字是自动分配给每个原子的内部 key。你可以通过 debugLabel 给原子添加标签,使它们更容易区分。

const countAtom = atom(0)
// countAtom's debugLabel by default is 'atom1'
if (process.env.NODE_ENV !== 'production') {
countAtom.debugLabel = 'count'
// debugLabel is 'count' now
}

Jotai 同时提供了 Babel 和 SWC 插件,能够自动为每个原子添加 debugLabel,让事情变得更简单。更多信息请查看 jotai-babel@swc-jotai/debug-label

你可以使用 React Dev Tools 来检查 Jotai 的状态。这是通过在自定义 hook 内部使用 useDebugValue 实现的。请注意,它仅在开发模式下有效(即 NODE_ENV === 'development')。

useAtom 会对原子值调用 useDebugValue。因此,如果你在 React Dev Tools 中选择一个使用了 Jotai 原子的组件,你将看到该组件中使用的每个原子都有一个 “Atom” hook,以及它当前的值。

useAtomsDebugValue 会捕获 Provider 下组件树中的所有原子(或在无 Provider 模式下捕获整个树中的原子),并对所有原子值调用 useDebugValue。 如果你在 React Dev Tools 中导航到包含 useAtomsDebugValue 的组件,你可以看到一个名为 “AtomsDebugValue” 的自定义 hook,它允许你查看所有原子的值及其依赖关系。

一个常见的用法是将这个 hook 放在 Provider 组件的正下方:

const DebugAtoms = () => {
useAtomsDebugValue()
return null
}
const Root = () => (
<Provider>
<DebugAtoms />
<App />
</Provider>
)

你也可以使用 Redux DevTools 来检查原子,它提供了时间旅行和值分发等多种功能。

useAtomDevtools 是一个 React hook,用于管理特定原子的 ReduxDevTools 扩展。

如果你想调试某个特定的原子,useAtomDevtools 是一个不错的选择。

const countAtom = atom(0)
// setting countAtom.debugLabel is recommended if we have more atoms
function Counter() {
const [count, setCount] = useAtom(countAtom)
useAtomDevtools(countAtom)
}

现在如果我们调用 setCount,可以看到 Redux Dev Tools 会立即记录这些变更。

有时我们需要切换到原子状态的某个特定值,时间旅行功能使这成为可能。 你可以在 devtools 中悬停在每个 action 上,看到 Jump 选项,点击即可切换到该特定值。

如果我们不想记录原子上的变更,可以使用暂停功能来停止监听。

可以使用分发功能来设置原子的值。点击 Show Dispatcher 按钮即可操作。 这会将 countAtoms 的值设置为 5

注意,该值会通过 JSON.parse 解析,因此请传入支持的值类型。

useAtomsDevtoolsuseAtomDevtools 的全量版本,它显示 Store 中所有原子的状态,而不是只显示某一个。

如果你想在一个地方追踪所有原子,我们推荐使用这个 hook。这意味着在此 hook 下方(React 树中)的每个原子上的每个操作都会被 Redux Dev Tools 捕获。

useAtomDevtools 的所有功能在这个 hook 中都受支持,此外还有一个额外的功能——提供关于原子依赖关系的更多信息,例如:

{
"values": {
"atom1:count": 0,
"atom2:doubleCount": 0,
"atom3:half": 0,
"atom4:sum": 0
},
"dependents": {
"atom1:count": ["atom1:count", "atom2:doubleCount", "atom4:sum"],
"atom2:doubleCount": ["atom3:half", "atom4:sum"],
"atom3:half": ["atom4:sum"],
"atom4:sum": []
}
}

为了发现意外修改存储在原子中对象的 bug,你可以使用 jotai/utils 中的 freezeAtomfreezeAtomCreator。 它们返回的原子值会通过 Object.freeze 被深度冻结。

freezeAtom(anAtom): AtomType

freezeAtom 接受一个现有的原子并将其”冻结”。 它返回同一个原子。 原子的值将通过 Object.freeze 被深度冻结。 这对于发现无意中修改对象(状态)的 bug 非常有用,因为这类修改可能导致意想不到的行为。 你可以对所有原子使用 freezeAtom 来防止这种情况。

anAtom(必填):你希望冻结的原子。

import { atom } from 'jotai'
import { freezeAtom } from 'jotai/utils'
const objAtom = freezeAtom(atom({ count: 0 }))

如果需要,你可以为 freezeAtom 定义一个工厂函数。

import { freezeAtom } from 'jotai/utils'
export function freezeAtomCreator<
CreateAtom extends (...args: unknown[]) => Atom<unknown>,
>(createAtom: CreateAtom): CreateAtom {
return ((...args: unknown[]) => freezeAtom(createAtom(...args))) as never
}