useState React 钩子总是返回初始值
useState React hook always returning initial value
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
总是记录 []
。我已经尝试在常规反应中做完全相同的事情 class 并且它工作正常,这让我认为我使用的钩子是错误的。
如有任何建议,我们将不胜感激。
更新:删除 useEffect
([history]
) 的第二个参数可以修复它。但为什么?目的是这种效果不需要在每次重新渲染时重新运行。因为它不应该需要。我认为这就是效果器的工作方式。
添加一个空数组也会破坏它。似乎 [locationHistory]
必须作为第二个参数添加到 useEffect
以阻止它中断(或者根本没有第二个参数)。但是我很困惑为什么这会阻止它破裂? history.listen
应该 运行 任何时候位置改变。为什么useEffect
每次locationHistory
改变都需要重新运行,以避免上述问题?
P.S。在这里玩一下: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
});
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
总是记录 []
。我已经尝试在常规反应中做完全相同的事情 class 并且它工作正常,这让我认为我使用的钩子是错误的。
如有任何建议,我们将不胜感激。
更新:删除 useEffect
([history]
) 的第二个参数可以修复它。但为什么?目的是这种效果不需要在每次重新渲染时重新运行。因为它不应该需要。我认为这就是效果器的工作方式。
添加一个空数组也会破坏它。似乎 [locationHistory]
必须作为第二个参数添加到 useEffect
以阻止它中断(或者根本没有第二个参数)。但是我很困惑为什么这会阻止它破裂? history.listen
应该 运行 任何时候位置改变。为什么useEffect
每次locationHistory
改变都需要重新运行,以避免上述问题?
P.S。在这里玩一下: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
});