Получил проект в react-native
+ expo
+ react-native-web
, мне нужно показать имя пользователя или ссылку для входа через файл макета в зависимости от того, хранится ли имя пользователя в хранилище.
приложение/_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.info('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.info('username from storage: ', v)
Я вижу, как эта строка журнала в консоли Chrome печатается бесконечно быстро, а процессор загружен.
Итак, как избежать этого бесконечного цикла, кроме добавленного мной if (username !== v)
, что, на мой взгляд, не элегантно.
Вызов storageUtil.getItem
приводит к установке имени пользователя с помощью setUsername
, что вызывает повторный рендеринг компонента, что вызывает вызов storageUtil.getItem
, и снова и снова.
Чтобы предотвратить это, вам нужно использовать одноразовый useEffect
useEffect(() => {
storageUtil.getItem(constStorage.keys.username).then(v => {
setUsername(v);
})
}, []);
Кажется, мне лучше использовать
useEffect()
без параметра, []
, иначе после успешного входа в систему имя пользователя не отображается, вместо этого по-прежнему отображается ссылка для входа, что означает, что содержимое внутри useEffect() не выполняется при переходе из /login в /home черезrouter.replace('/home');
.