自定义钩子中的 setState 调用不会更新状态



我正在尝试设置一个基本的自定义钩子来返回 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;```

您的示例有效...

setOrientation实际上会改变orientation的状态值,useDeviceDimensions会返回更改后的orientation。问题在于你把console.log语句放在哪里 - 你是对的,这与传递给useEffect的闭包(及其范围(有关。

useEffect仅使用定义的回调调用一次。此回调是一个闭包,可以从useState访问orientation。在创建闭包时,orientation变量的值将为null。因为从来没有创建一个新的闭包([]useEffect依赖项(,所以当包含的更改侦听器被触发时,它将始终打印值null

但是,setDimensions内部setOrientation将调度并将更改传达给 React。流程是这样的:

  1. useEffect闭包在首次呈现时调用一次。
  2. 稍后会触发change事件。
  3. 闭包内部的setDimensions始终从函数外部范围orientation变量(在构造时具有值null(中打印相同的值。
  4. setOrientation被调用,React 会在内部更新状态并在父组件中触发新的渲染周期。
  5. useDeviceDimensions从父组件再次调用,它现在具有并返回新的orientation状态。
  6. 触发新的更改,再次继续执行 3。

第 4 点在闭包中起作用,因为 React 为每个组件都有一个内部的"存储单元"列表,它可以在其中读取和更新最近的状态,因此更新在整个闭包范围内工作(有关更多信息,请参阅此处(。读取端orientation是一个过时的变量,如果你愿意的话,它只引用了 React 最初存储的第一个状态值。

。但最好以安全的方式声明useEffect

您的useEffect钩子使用您在其依赖项数组中未提及的状态。React 文档对此有何评论:

如果使用此优化,请确保数组包含组件范围(例如 props 和 state(中随时间变化并由效果使用的所有值。否则,代码将引用以前呈现中的过时值。链接

所以如果你也想在useEffect中使用orientation,你可以将其声明为依赖项:

useEffect(() => {
...
}, [orientation]);

看看这个代码沙盒的例子,希望它能澄清一些事情!

相关内容

  • 没有找到相关文章

最新更新