React Expo:数据获取与状态变更后如何触发页面重渲染
问题分析与解决方案
核心问题
页面无法自动重渲染的关键原因是冗余本地state导致Redux状态更新无法同步到视图:你通过useSelector获取了Redux中的用户数据,却额外将其复制到本地statecurrentProfilePage中,异步赋值过程导致视图无法及时响应Redux状态变化;同时加载状态判断依赖本地state,进一步加剧了渲染延迟。
具体优化点
- 移除冗余本地state:直接使用
useSelector返回的Redux数据,无需通过currentProfilePage中转 - 简化Effect逻辑:删除不必要的state同步Effect,减少异步更新带来的不一致
- 修复加载状态管理:在数据请求开始/结束时更新
isLoading,精准控制加载提示
修改后的代码
import { StatusBar } from 'expo-status-bar'; import { Button, StyleSheet, Text, TextInput, View, ScrollView, Image, FlatList, RefreshControl} from 'react-native'; import React, {useState, useEffect} from 'react' import Icon from 'react-native-vector-icons/Feather'; import IconV from 'react-native-vector-icons/FontAwesome5'; import IconM from 'react-native-vector-icons/MaterialCommunityIcons'; import { useNavigation } from '@react-navigation/core'; import { useDispatch, useSelector } from 'react-redux'; import Header from '../src/components/Header'; import { TouchableOpacity } from 'react-native-gesture-handler'; import { auth } from '../firebase'; import { updateProfile } from "firebase/auth"; import * as profilePageAction from '../redux/actions/profilePageAction'; const MyProfileScreen = props => { const [userEmail, setUserEmail] = useState(); const [userName, setUserName] = useState(); const [isLoading, setIsLoading] = useState(true); const [refreshing, setRefreshing] = useState(false); const user = auth.currentUser; const navigation = useNavigation(); const dispatch = useDispatch(); const FirebaseID = user.uid; // 直接使用Redux中的用户数据,无需中转到本地state const profilePage = useSelector(state => state.profilePage.profilePages.find(page => page.FirebaseID === FirebaseID)); useEffect(() =>{ // 请求开始时标记加载状态 setIsLoading(true); dispatch(profilePageAction.fetchProfilePages()) .then(() => { // 请求成功后关闭加载状态 setIsLoading(false); if(profilePage){ setUserEmail(profilePage.Email); } }) .catch(err => { console.log(err); // 请求失败也需关闭加载状态 setIsLoading(false); }); }, [dispatch, FirebaseID]); // 当Redux中用户数据变化时,同步更新本地邮箱状态(可选,视图可直接用profilePage.Email) useEffect(() =>{ if(profilePage){ setUserEmail(profilePage.Email); } }, [profilePage]) return ( <View style={styles.container}> <View style={styles.emailContainer}> {/* 基于加载状态和Redux数据判断渲染内容 */} {isLoading ? <Text style={styles.email}>Loading Data...</Text> : profilePage ? <Text>{profilePage.Email}</Text> : <Text style={styles.email}>未找到用户数据</Text> } </View> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center', }, emailContainer:{ backgroundColor: '#000000', height: '15%', padding: 10 }, list:{ shadowColor: 'black', shadowOpacity: 0.25, shadowOffset: {width: 0 , height: 2}, shadowRadius: 8, borderRadius: 10, backgroundColor: 'white', elevation: 5, height: 300, width: 200, margin: 10 }, email: { fontSize: 15, color: 'gray' } }); export default MyProfileScreen;
额外说明
- Redux的
useSelector会自动订阅状态变化,当profilePages更新时组件会自动重渲染,无需手动同步到本地state - 加载状态
isLoading需在请求全周期内明确设置,避免加载提示异常显示 - 视图可直接使用
profilePage.Email,无需额外存储到userEmail本地state,可进一步简化代码
内容的提问来源于stack exchange,提问作者Osman Elsoz
相关产品推荐
相关产品推荐

