我正在尝试建立一个基本的自定义钩子,以在React Native中返回设备方向。我旁边有一个功能代码示例,我不知道为什么这行不通。我认为这是某种封闭/范围确定问题,但显然我不知道。
我知道有一些更简单的方法来确定设备方向,但是我想知道为什么它不起作用以及如何使其起作用。
当前行为:调用setOrientation
不会更改orientation
的值。
预期的行为:调用setOrientation
会更新orientation
的值。
一旦发生这种情况,我认为该挂钩将正常运行,因为每次更新null
时,挂钩都会返回Dimensions
。
[更新:为清楚起见进行了编辑]
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;```
答案 0 :(得分:2)
setOrientation
实际上将更改状态orientation
,而useDeviceDimensions
将返回更改后的orientation
。问题在于您放置console.log
语句的位置-是的,这与传递给useEffect
的闭包(及其范围)有关。
useEffect
与定义的回调一起调用only once。此回调是一个闭包,可以从orientation
访问useState
。在创建闭包时,orientation
变量将具有值null
。因为从未创建新的闭包([]
中的useEffect
依赖项),所以当触发包含的更改侦听器时,它将始终打印值null
。
但是,setOrientation
中的setDimensions
将调度更改并将其传达给React。流程是这样的:
useEffect
闭包在第一次渲染时被调用一次。change
事件。setDimensions
始终在函数外部作用域orientation
变量(在构造时其值为null
)中打印相同的值。setOrientation
被调用,React内部更新状态并在父组件中触发新的渲染周期。useDeviceDimensions
从父组件再次被调用,它现在具有并返回新的orientation
状态。第4点在闭包中起作用,因为React在每个组件内部都有一个“内存单元”列表,它可以读取和更新最近的状态,因此更新在闭包范围内起作用(请参阅here更多信息)。读取端orientation
是一个陈旧的变量(如果您愿意的话),它仅引用了React最初存储的第一个状态值。
useEffect
您的useEffect
钩子使用您在依赖项数组中未提及的状态。 React文档对此有何评论:
如果使用此优化,请确保数组包含组件范围中所有随时间变化且被效果使用的值(例如props和state)。否则,您的代码将引用先前渲染中的陈旧值。 Link
因此,如果您还想在orientation
中使用useEffect
,则可以将其声明为依赖项:
useEffect(() => {
...
}, [orientation]);
以这个Codesandbox为例,希望它能使您澄清一些事情!