首页 > 解决方案 > useState React 钩子总是返回初始值

问题描述

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总是记录[]。我尝试在常规反应类中做完全相同的事情并且它工作正常,这让我认为我使用错误的钩子。

任何建议将不胜感激。

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

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

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

标签: reactjsreact-hooks

解决方案


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. 您不应该像使用 the 那样直接使用它locationHistory(可以,但如果这样做,您需要将它添加到依赖项数组中,并且您的效果将在每次更改时运行)。为了避免直接访问它并将其添加到依赖数组中,您可以这样做,使用方法的函数形式setState

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

推荐阅读