在
react-native
+ expo
+ react-native-web
中有一个项目,我需要通过布局文件显示用户名或登录链接,具体取决于用户名是否存储在存储中。
app/_layout.tsx:
import React, {useState} from 'react';
import {SafeAreaView, StyleSheet, Text, View} from 'react-native';
import {Link, Slot} from "expo-router";
import Constants from "expo-constants/src/Constants";
import storageUtil from "@/utils/storage";
import constStorage from "@/constants/Storage";
export default () => {
// username from storage, indicate whether already login,
const [username, setUsername] = useState<string | null>(null);
storageUtil.getItem(constStorage.keys.username).then(v => {
console.log('username from storage: ', v)
if (username !== v) // add to avoid infinite loop, TODO: improve.
setUsername(v)
})
return (
<SafeAreaView style={styles.container}>
<View id='header' style={{flex: 1}}><Text>
{username ?
(<Link href="/home">{username}</Link>)
: (<Link href="/login">Login</Link>)
}
</Text></View>
<View id='main' style={{flex: 2, width: '100%', minHeight: 350, padding: 8}}>
<Slot/>
</View>
<View id='footer' style={{flex: 3}}><Text>Footer</Text></View>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
paddingTop: Constants.statusBarHeight, // don't go to statusbar of phone,
flex: 1,
backgroundColor: '#FFF',
position: 'relative',
alignItems: 'center',
justifyContent: 'center',
},
})
如果我删除行
if (username !== v)
,在浏览器中,当我单击username
或Login
链接时,它会触发无限循环。 console.log('username from storage: ', v)
我可以看到 chrome 控制台中的这条日志行无限快速地打印出来,并且 cpu 很高。
那么,除了我添加的
if (username !== v)
之外,如何避免这种无限循环,我认为这并不优雅。
调用
storageUtil.getItem
会导致使用 setUsername
设置用户名,导致组件重新渲染,导致调用 storageUtil.getItem
,如此反复。
为了防止这种情况,你需要使用一次性 useEffect
useEffect(() => {
storageUtil.getItem(constStorage.keys.username).then(v => {
setUsername(v);
})
}, []);