自定义挂钩内的 setState 调用未更新状态
Posted
技术标签:
【中文标题】自定义挂钩内的 setState 调用未更新状态【英文标题】:setState call inside a custom hook is not updating the state 【发布时间】:2020-01-23 01:56:37 【问题描述】:我正在尝试设置一个基本的自定义挂钩来返回 React Native 中的设备方向。我旁边有一个功能代码示例,但我不知道为什么这不起作用。我认为这是某种关闭/范围问题,但显然我不知道。
我知道有更简单的方法来获取设备方向,但我想知道为什么这不起作用以及如何使它起作用。
当前行为:调用setOrientation
不会更改orientation
的值。
预期行为:调用setOrientation
会更新orientation
的值。
一旦发生这种情况,我认为钩子会正常工作,因为每次Dimensions
更新时它都会返回null
。
[更新:为清楚起见进行了编辑]
import Dimensions, from 'react-native';
function useDeviceDimensions()
const [orientation, setOrientation] = useState(null);
useEffect(() =>
const setDimensions = (e) =>
console.log('running', orientation); // null
const width, height = e.window;
setOrientation(width > height ? 'landscape' : 'portrait');
;
Dimensions.addEventListener('change', setDimensions);
return () => Dimensions.removeEventListener('change', setDimensions);
, [])
return orientation;
export default useDeviceDimensions;```
【问题讨论】:
useDeviceDimensions
函数返回的对象的属性永远不会改变,这与 React 无关。只是因为你从不改变返回的对象,你重新定义了它包含的一些变量。
只能在这里猜测,您所说的“这不起作用”是什么意思 - orientation
应该可以正常工作。您不会在维度更改时更新/调用 setWidth
和 setHeight
。
@Titus 你能详细说明一下吗?我不明白我的代码如何重新定义状态变量而不是更新它们。
@ford04 请查看更新后的代码 - 我取出了未使用的部分,以便更清楚我要做什么。
我的意思是,从外观上看,您使用的是useDeviceDimensions
的返回值,如果是这样的话,这个返回值(orientation
)不会改变如果你在函数内部重新定义它。
【参考方案1】:
您的示例有效...
setOrientation
实际上会改变orientation
的状态值,useDeviceDimensions
会返回改变后的orientation
。问题在于您放置 console.log
语句的位置 - 您是对的,这与传递给 useEffect
的闭包(及其范围)有关。
useEffect
使用您定义的回调调用 only once。这个回调是一个闭包,可以从useState
访问orientation
。在创建闭包时,orientation
变量将具有值null
。因为永远不会创建新的闭包(useEffect
中的[]
依赖项),所以当触发包含的更改侦听器时,它将始终打印值null
。
但是,setDimensions
内部的 setOrientation
将分派并将更改传达给 React。流程是这样的:
useEffect
闭包在第一次渲染时被调用一次。
稍后会触发change
事件。
闭包内的setDimensions
始终从函数外部作用域orientation
变量(在构造时具有值null
)打印相同的值。
setOrientation
被调用,React 内部更新状态并在父组件中触发新的渲染周期。
useDeviceDimensions
再次从父组件调用,它现在拥有并返回新的 orientation
状态。
触发了新的更改,再次执行 3。
第 4 点适用于闭包,因为 React 为每个组件都有一个“内存单元”的内部列表,它可以在其中读取和更新最近的状态,因此更新可以在闭包范围内工作(有关更多信息,请参阅 here )。读取端 orientation
是一个陈旧的变量,如果你愿意的话,它只是对 React 最初存储的第一个状态值的引用。
...但最好以安全的方式声明useEffect
您的 useEffect
钩子使用了您在其依赖项数组中未提及的状态。 React 文档对此有何评论:
如果您使用此优化,请确保数组包含组件范围内的所有值(例如 props 和 state),这些值会随时间变化并被效果器使用。否则,您的代码将引用以前渲染中的陈旧值。 Link
所以如果你还想在useEffect
中使用orientation
,你可以将它声明为依赖:
useEffect(() =>
...
, [orientation]);
以Codesandbox 为例,希望它能澄清一点!
【讨论】:
以上是关于自定义挂钩内的 setState 调用未更新状态的主要内容,如果未能解决你的问题,请参考以下文章