Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] useWatch #2748

Open
hou-pu opened this issue Mar 27, 2025 · 1 comment
Open

[RFC] useWatch #2748

hou-pu opened this issue Mar 27, 2025 · 1 comment

Comments

@hou-pu
Copy link

hou-pu commented Mar 27, 2025

  • 简介:
    用于主动观测数据的变化,执行对应操作。

  • 为什么需要:
    useWatch相当于依赖前置,主动声明依赖相比useEffect系列,使用时的心智是先思考自己要用到的数据依赖,再写回调函数,这样对于自己要做的事情很明确,而不是像useEffect一样,先写回调函数,再看看用到了哪些依赖,这样很容易遗漏依赖项。

  • 设计参考
    参考Vue的watch函数设计。

API

function useWatch<T>(
  source: WatchSource<T>,
  callback: WatchCallback<T>,
  options: WatchOptions = {}
): WatchHandle

type WatchSource<T> = T | (() => T)
type WatchCallback<T> = (value: T, oldValue?: T) => CleanupFn | void
type CleanupFn = () => void

interface WatchOptions {
  // 只触发一次,默认:false
  once?: boolean
  // 深度比较,默认:false
  deep?: boolean
  // 挂载后立即触发,默认:false
  mount?: boolean
  // 触发时机默认 `post`
  flush?: EffectType
}

interface WatchHandle {
  // 暂停触发
  pause: () => void
  // 继续触发
  resume: () => void
}

// 触发时机
type EffectType =
  // 与useLayoutEffect时机相同
  | 'pre'
  // 立即同步触发
  | 'sync'
  // 与useEffect时机相同
  | 'post'

Demo

// 观测普通值
const [x, setX] = useState(0)
useWatch(x, (value, oldValue) => {
  console.log('当前值:', value) // 1
  console.log('上一次的值:', oldValue) // 0
  return () => {
    // 清理上一次的操作...
  }
})
setX(1)

// 使用函数计算一个结果
const [x, setX] = useState(0)
useWatch(() => x + 1, (value, oldValue) => {
  console.log('当前值:', value) // 2
  console.log('上一次的值:', oldValue) // 1
})
setX(1)

// 深度观测对象变化
const [obj, setObj] = useState({a: 1})
const [obj2, setObj2] = useState({b: 1})
useWatch({ obj, obj2 }, (value, oldValue) => {
  console.log('当前值:', value) // { obj: {a: 2}, obj2: {b:1} }
  console.log('上一次的值:', oldValue) // { obj: {a: 1}, obj2: {b:1} }
}, { deep: true })
setObj({a: 2})

// 深度观测数组变化
const [obj, setObj] = useState({a: 1})
const [obj2, setObj2] = useState({b: 1})
useWatch([obj, obj2], (value, oldValue) => {
  console.log('当前值:', value) // [{a: 2}, {b: 1}]
  console.log('上一次的值:', oldValue) // [{a: 1}, {b: 1}]
}, { deep: true })
setObj({a: 2})
@tkgkn
Copy link

tkgkn commented Apr 7, 2025

eslint里配置 react-hooks/exhaustive-deps 应该能解决你的问题了。vscode等ide会有提示,也可以声明为error级别。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants