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
应在位置更改时随时运行。为什么每次locationHistory
更改时都需要再次运行useEffect
以避免上述问题?
附言在这里玩弄它:https://codesandbox.io/s/react-router-ur4d3?fontsize=14(感谢lissitz在那里做了大部分的腿部工作)
您正在为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
});