Jotai 中如何正确监听 atom 值的变化?

端木诗诗 阅读 45

我在用 Jotai 管理状态,想在某个 atom 的值变化时执行副作用(比如发请求),但 useEffect 里监听 atom 总是拿不到最新值,或者触发多次。我试过直接把 atom 放进依赖数组,也试过用 useAtomValue,都不太对。

比如下面这段代码,每次 count 变化时我都想打印出来,但实际没反应:

import { useAtom, atom } from 'jotai'

const countAtom = atom(0)

function MyComponent() {
  const [count] = useAtom(countAtom)
  
  useEffect(() => {
    console.log('count changed:', count)
  }, [countAtom]) // 这里是不是写错了?
  
  return <div>{count}</div>
}
我来解答 赞 5 收藏
二维码
手机扫码查看
2 条解答
设计师恩硕
你的问题在于依赖数组写错了,[countAtom] 应该改成 [count]

useEffect 的依赖数组是用来告诉 React 什么时候重新执行这个 effect 的,你写 countAtom 的话,这个 atom 引用永远不变,所以 effect 不会重新触发。你应该监听实际变化的值 count

改一下就是这样:

import { useAtom, atom } from 'jotai'
import { useEffect } from 'react'

const countAtom = atom(0)

function MyComponent() {
const [count] = useAtom(countAtom)

useEffect(() => {
console.log('count changed:', count)
}, [count]) // 改成 count

return
{count}

}


这样就能正常打印了。

不过我之前踩过另一个坑,如果你用的是 useAtomValue 而不是 useAtom,其实可以更简洁:

import { useAtomValue, useSetAtom } from 'jotai'
import { useEffect } from 'react'

const countAtom = atom(0)

function MyComponent() {
const count = useAtomValue(countAtom)
const setCount = useSetAtom(countAtom)

useEffect(() => {
console.log('count changed:', count)
}, [count])

return
setCount(c => c + 1)}>{count}

}


如果你的需求是在 atom 变化时执行副作用但不想重新渲染组件,可以看看 atom.withReducer 或者在 atom 层面用 onRead/onWrite 回调,不过大多数场景用 useEffect 监听值就够用了。
点赞
2026-03-20 03:00
IT人筱萌
兄弟,你这个依赖数组写错了。useEffect 的第二个参数应该是具体要监听的变量,你放 countAtom 进去那肯定不行啊,React 又不知道你要监听 atom 的什么。

正确写法是这样的:

import { useAtom } from 'jotai'

const countAtom = atom(0)

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

useEffect(() => {
console.log('count changed:', count)
}, [count]) // 监听 count 这个值本身

return
setCount(c => c + 1)}>{count}

}


[countAtom] 改成 [count] 就对了,useEffect 会监听 count 的变化,变化时执行回调。

如果你用的是 useAtomValue(只读不写),写法也一样:

import { useAtomValue } from 'jotai'
import { useEffect } from 'react'

const countAtom = atom(0)

function MyComponent() {
const count = useAtomValue(countAtom)

useEffect(() => {
console.log('count changed:', count)
}, [count])

return
{count}

}


另外提醒一下,useEffect 在组件挂载时也会执行一次,如果只想在更新时执行,可以加个 ref 判断:

const isMounted = useRef(false)

useEffect(() => {
if (!isMounted.current) {
isMounted.current = true
return
}
console.log('count changed:', count)
}, [count])


这样就只在 count 变化时打印了。
点赞 1
2026-03-13 21:02