useContext 未在回调中更新其值

Posted

技术标签:

【中文标题】useContext 未在回调中更新其值【英文标题】:useContext not updating its value in callback 【发布时间】:2020-02-16 23:12:21 【问题描述】:

useConext 值在我附加到wheel 事件的回调中没有更新。我试图安慰但仍在打印静态值。但在回调之外,它正在打印更新的值

const Home = () => 
  //accessing my context
  var [appState, dispatch] = useContext(CTX);
  //printing updated value here (working perfect here)
  console.log(appState);

  //my callback on wheel event (also using debouce to queue burst of events)
  var fn = debounce(e => 
    //incrementing value ++1
    dispatch( type: 'INCREMENT_COMPONENT_COUNTER' );
    //printing static value here (problem here)
    console.log(appState);
  , 500);

  //setting and removing listener on component mount and unmount
  useEffect(() => 
    window.addEventListener('wheel', fn);
    return () => 
      window.removeEventListener('wheel', fn);
    ;
  , []);
;

【问题讨论】:

【参考方案1】:

在挂载时,侦听器使用一个函数变量进行初始化,该变量将appStore 的第一个值包含在其词法范围内。

请参阅Closures。

要修复它,请将其移动到 useEffect 范围内。

const Home = () => 
  const [appState, dispatch] = useContext(CTX);

  useEffect(() => 
    const fn = debounce(e => 
      dispatch( type: 'INCREMENT_COMPONENT_COUNTER' );

      console.log(appState);
    , 500);

    window.addEventListener('wheel', fn);
    return () => 
      window.removeEventListener('wheel', fn);
    ;
  , [appState]);
;

友情提示:

使用linter like eslint - 它应该警告你在useEffect 中使用appState Don't use var - 容易出错。

【讨论】:

您能否详细说明为什么原始解决方案不起作用?这是否意味着每次调用 dispatch 时 appState 都会发生变化? (即,appState 不是指针,因此它始终包含原始值)。 appState 上有一个闭包,所以它的值在下一次渲染时是陈旧的 嗯,是的,但是如果 appState 是一个指针,那不会有问题,因为 appState 本身不会改变,但它指向的值会。我不确定是否真的了解这里发生的事情。 即使它是一个“指针”appState=someValue,如果 appState 对象会改变:appState=someValue, otherValue 监听器中的值将是陈旧的。 所以如果我理解正确,dispatch 正在修改appState 的值而不是对象本身,这就是为什么它不起作用? (这里是my question,没有歧义)【参考方案2】:

您的 debance 函数在每次渲染中都会发生变化,而 useEffect 仅捕获第一个渲染,您可以使用 useCallback 解决此问题:

const Home = () => 
  // accessing my context
  const [appState, dispatch] = useContext(CTX)
  // printing updated value here (working perfect here)
  console.log(appState)

  // my callback on wheel event (also using debouce to queue burst of events)
  const fn = useCallback(
    () =>
      debounce(e => 
        // incrementing value ++1
        dispatch( type: 'INCREMENT_COMPONENT_COUNTER' )
        // printing static value here (problem here)
        console.log(appState)
      , 500),
    [appState, dispatch],
  )

  // setting and removing listener on component mount and unmount
  useEffect(() => 
    window.addEventListener('wheel', fn)
    return () => 
      window.removeEventListener('wheel', fn)
    
  , [fn])

【讨论】:

仍然无法正常工作。由于您在 useEffect 依赖数组中添加了 fn,因此它在每次 fn 更新时都附加了 wheel 事件。我将这个数组留空的原因是这个 useEffect 只会在 mount 和 unmount 监听器上运行一次,因为我在 useEffect 中添加了 return,所以在卸载发生后。

以上是关于useContext 未在回调中更新其值的主要内容,如果未能解决你的问题,请参考以下文章

useContext 未在子组件中显示更新的状态(当从全局文件中的 useEffect 挂钩中的 firebase 检索数据时)

useState 中的变量未在 useEffect 回调中更新

自定义元框 Save_Post 回调未在 functions.php 中触发

状态未在地理定位功能中使用 setState 进行更新

React.useContext 没有更新

(React、MaterialUI、Context)MUI 自动完成/TextField 未在挂载时呈现其值