You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native离线重启Context值未加载及重复渲染问题求助

修复React Native离线模式下Context状态丢失与无限重渲染问题

核心问题分析

  1. NetInfo监听用法错误:你把NetInfo.addEventListener返回的取消订阅函数当成了状态获取函数调用,导致监听立即被移除,网络状态永远是初始的false,且无法监听后续变化。
  2. 离线数据判断逻辑缺陷:用JSON.stringify(offlineData) !== storedData做比较,不仅性能差,还可能因为数组元素的顺序、格式问题导致误判,触发不必要的setOfflineData,进而引发重渲染循环。
  3. 异步初始化逻辑混乱:多个异步操作并行执行,没有处理竞态,且缺少必要的状态更新判断(比如权限状态已经是true时,没必要再调用setState)。

修复后的完整代码

import React, { createContext, useState, useEffect } from 'react';
import NetInfo from '@react-native-community/netinfo';
import AsyncStorage from '@react-native-async-storage/async-storage';

// 假设这些key是你定义的常量
const loginKey = 'USER_LOGIN_KEY';
const offlineKey = 'OFFLINE_DATA_KEY';

interface AppContextValue {
  login: string;
  setLogin: (loggedIn: string) => void;
  hasInternetConnection: boolean;
  setInternetConnection: (hasConnection: boolean) => void;
  hasCameraPermissions: boolean;
  setCameraPermissions: (hasCameraPermissions: boolean) => void;
  hasLocationPermissions: boolean;
  setLocationPermissions: (hasLocationPermissions: boolean) => void;
  offlineData: any[];
  setOfflineData: (offlineData: any[]) => void;
}

const AppContext = createContext<AppContextValue>({
  login: '',
  setLogin: () => {},
  hasInternetConnection: false,
  setInternetConnection: () => {},
  hasCameraPermissions: false,
  setCameraPermissions: () => {},
  hasLocationPermissions: false,
  setLocationPermissions: () => {},
  offlineData: [],
  setOfflineData: () => {},
});

interface AppProviderProps {
  children: React.ReactNode;
}

// 假设这两个权限请求函数是你定义的
const requestCameraPermission = async (): Promise<boolean> => {
  // 你的权限请求逻辑
  const result = await /* 实际权限请求代码 */;
  return result === 'granted';
};

const requestLocationPermission = async (): Promise<boolean> => {
  // 你的权限请求逻辑
  const result = await /* 实际权限请求代码 */;
  return result === 'granted';
};

export const AppProvider: React.FC<AppProviderProps> = ({ children }) => {
  const [login, setLogin] = useState('');
  const [hasInternetConnection, setInternetConnection] = useState(false);
  const [hasCameraPermissions, setCameraPermissions] = useState(false);
  const [hasLocationPermissions, setLocationPermissions] = useState(false);
  const [offlineData, setOfflineData] = useState<any[]>([]);

  // 存储离线数据到AsyncStorage
  useEffect(() => {
    const storeOfflineData = async () => {
      try {
        if (offlineData.length > 0) {
          await AsyncStorage.setItem(offlineKey, JSON.stringify(offlineData));
        }
      } catch (error) {
        console.error('Error storing offline data:', error);
      }
    };

    storeOfflineData();
  }, [offlineData]);

  // 初始化所有状态:网络、登录、权限、离线数据
  useEffect(() => {
    // 注册网络状态监听
    const unsubscribeNetInfo = NetInfo.addEventListener((state) => {
      // 只有当状态变化时才更新,避免不必要的重渲染
      if (state.isConnected !== hasInternetConnection) {
        setInternetConnection(!!state.isConnected);
      }
    });

    // 统一处理所有异步初始化逻辑
    const initializeApp = async () => {
      // 1. 获取存储的登录信息
      const userNumber = await AsyncStorage.getItem(loginKey);
      if (userNumber && userNumber !== login) {
        setLogin(userNumber);
      }

      // 2. 检查相机权限
      const cameraPermission = await requestCameraPermission();
      if (cameraPermission !== hasCameraPermissions) {
        setCameraPermissions(cameraPermission);
      }

      // 3. 检查位置权限
      const locationPermission = await requestLocationPermission();
      if (locationPermission !== hasLocationPermissions) {
        setLocationPermissions(locationPermission);
      }

      // 4. 获取离线数据:仅在初始加载时覆盖,避免循环
      const storedData = await AsyncStorage.getItem(offlineKey);
      if (storedData) {
        const parsedData = JSON.parse(storedData);
        // 简单比较长度,避免JSON.stringify的性能问题
        if (parsedData.length !== offlineData.length) {
          setOfflineData(parsedData);
        }
      }
    };

    initializeApp();

    // 组件卸载时清理网络监听
    return () => {
      unsubscribeNetInfo();
    };
  }, [login, hasCameraPermissions, hasLocationPermissions, offlineData.length]);

  return (
    <AppContext.Provider
      value={{
        login,
        hasInternetConnection,
        setLogin,
        setInternetConnection,
        hasCameraPermissions,
        setCameraPermissions,
        hasLocationPermissions,
        setLocationPermissions,
        offlineData,
        setOfflineData,
      }}
    >
      {children}
    </AppContext.Provider>
  );
};

export default AppContext;

关键修复点说明

  • NetInfo监听修复:不再调用返回的取消订阅函数,而是保存该函数在组件卸载时执行,确保网络状态可以被正确监听,同时增加状态变化判断,避免不必要的更新。
  • 异步初始化逻辑合并:将所有异步操作放在同一个initializeApp函数中,避免并行执行的竞态问题,同时每个状态更新前都做了当前值对比,减少不必要的重渲染。
  • 离线数据判断优化:用数组长度对比替代JSON.stringify,既提升性能,又避免因序列化格式差异导致的误判;且仅在初始加载时覆盖数据,避免循环触发存储逻辑。
  • 权限请求优化:权限请求后对比当前状态,只在状态变化时调用setState,减少无效重渲染。

内容的提问来源于stack exchange,提问作者user18370307

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 06:02:32