【问题标题】:useState React hook always returning initial valueuseState React 钩子总是返回初始值
【发布时间】:2019-07-25 23:28:03
【问题描述】:

locationHistory 在以下代码中始终是一个空数组:

export function LocationHistoryProvider({ history, children }) {
  const [locationHistory, setLocationHistory] = useState([])

  useEffect(() => history.listen((location, action) => {
    console.log('old state:', locationHistory)
    const newLocationHistory = locationHistory ? [...locationHistory, location.pathname] : [location.pathname]
    setLocationHistory(newLocationHistory)
  }), [history])

  return <LocationHistoryContext.Provider value={locationHistory}>{children}</LocationHistoryContext.Provider>
}

console.log 始终记录 []。我尝试在常规的 react 类中做完全相同的事情,并且效果很好,这让我认为我使用了错误的钩子。

任何建议将不胜感激。

更新:删除useEffect ([history]) 的第二个参数可以修复它。但为什么?目的是不需要在每次重新渲染时重新运行此效果。因为它不应该是。我认为这就是效果器的工作方式。

添加一个空数组也会破坏它。似乎 [locationHistory] 必须作为第二个参数添加到 useEffect 以阻止它中断(或根本没有第二个参数)。但我很困惑为什么这会阻止它破裂? history.listen 应该在位置更改时运行。为什么useEffect每次locationHistory变化都需要重新运行一次,以避免出现上述问题?

附:在这里玩一下:https://codesandbox.io/s/react-router-ur4d3?fontsize=14(感谢 lissitz 在那里完成了大部分腿部工作)

【问题讨论】:

  • 嗯,真奇怪:s
  • @lissitz 我刚刚意识到您复制了错误的代码。您没有在正确的位置包含 [history] ​​变量。当我完全删除 [history] ​​参数时,它开始起作用。所以感谢您意外地为我找到了它:D 我仍然不知道为什么包含它会破坏它。

标签: reactjs react-hooks


【解决方案1】:

您正在为history 对象设置一个侦听器,对吧?

假设您的 history 对象在多个渲染中保持不变(相同的对象引用),您应该这样做:

  • 在第一次渲染后(即安装后)设置监听器
  • 卸载后删除监听器

为此,您可以这样做:

useEffect(()=>{
  history.listen(()=>{//DO WHATEVER});
  return () => history.unsubscribe(); // PSEUDO CODE. YOU CAN RETURN A FUNCTION TO CANCEL YOUR LISTENER
},[]);   // THIS EMPTY ARRAY MAKES SURE YOUR EFFECT WILL ONLY RUN AFTER 1ST RENDER

但如果您的 history 对象在每次渲染时都会发生变化,您需要:

  • 取消最后一个监听器(来自上一个渲染)和
  • 每次历史对象更改时设置一个新的侦听器。
useEffect(()=>{
  history.listen(()=>{//DO SOMETHING});
  return () => history.unsubscribe(); // PSEUDO CODE. IN THIS CASE, YOU SHOULD RETURN A FUNCTION TO CANCEL YOUR LISTENER
},[history]);   // THIS ARRAY MAKES SURE YOUR EFFECT WILL RUN AFTER EVERY RENDER WITH A DIFFERENT `history` OBJECT

注意:setState 函数保证在每个渲染中都是相同的实例。所以它们不需要在依赖数组中。

但是,如果您想访问 useEffect 中的当前状态。你不应该像使用locationHistory 那样直接使用它(你可以,但如果你这样做了,你需要将它添加到依赖数组中,你的效果会在每次它改变时运行)。为避免直接访问它并将其添加到依赖数组中,您可以这样做,使用setState 方法的函数形式。

setLocationHistory((prevState) => {
  if (prevState.length > 0) {
     // DO WHATEVER
  }
  return SOMETHING;  // I.E.: SOMETHING WILL BE YOUR NEW STATE
});

【讨论】:

  • 感谢您的回答。添加一个空数组也会以与问题中所述相同的方式破坏它。所以我必须添加一些东西(可能是locationHistory)作为useEffect 的第二个参数,以防止它崩溃。但我很困惑为什么这会阻止它破裂?另外,为什么访问useEffect 内部的当前状态是不好的做法?这就是官方教程所做的(reactjs.org/docs/hooks-effect.html)。附: history.listen(来自 npm history 库)返回一个 unlisten 函数,所以我不需要在那里做任何其他事情
  • 关于setLocationoHistory 的最后一点修复它(codesandbox.io/s/react-router-ur4d3?fontsize=14)我仍然不知道为什么,但我今晚会更多地研究这个,感谢您的洞察力! :)
  • 查看此常见问题解答:reactjs.org/docs/…。它解释了为什么有时您不想在效果中引用当前状态。
  • 啊,太棒了,正是我想要的,谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-05
  • 2021-05-20
  • 2019-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多