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

React Native Expo:引导页仅首次启动显示失效问题求助

解决引导页重复显示的问题

问题原因

你没有在用户完成引导流程(点击Skip或Done按钮)后,将isFirstTimeOpen存入AsyncStorage,所以每次重启App时,AsyncStorage里始终没有这个键,导致判断为首次启动,重复显示引导页。

修复步骤

1. 修改OnboardScreen,完成引导后标记状态

在onSkip和onDone回调中添加AsyncStorage存储操作,标记用户已完成引导:

import React from "react";
import { View, Text, TouchableOpacity, Image } from "react-native";
import Onboarding from "react-native-onboarding-swiper";
import AsyncStorage from '@react-native-async-storage/async-storage';

// 保留Skip、Next、Done、Dots组件代码不变
const Skip = ({...props}) => (
  <TouchableOpacity
    style={{
      backgroundColor: "#F4F4F4", 
      borderRadius: 10, 
      width: 90, 
      height: 40,
      padding: 5,
      alignItems: "center", 
      left: 25}}
    {...props}
  >
    <Text style={{fontSize: 18}}>Skip</Text>
  </TouchableOpacity>
)

const Next = ({...props}) => (
  <TouchableOpacity
    style={{
      backgroundColor: "#258671", 
      borderRadius: 10, 
      width: 90, 
      height: 40,
      padding: 5, 
      alignItems: "center", 
      right: 25}}
    {...props} 
  >
    <Text style={{fontSize: 18}}>Next</Text>
  </TouchableOpacity>
)

const Done = ({...props}) => (
  <TouchableOpacity
    style={{
      backgroundColor: "#258671", 
      borderRadius: 10, 
      width: 90, 
      height: 40,
      padding: 5, 
      alignItems: "center", 
      right: 25}}
    {...props} 
  >
    <Text style={{fontSize: 18}}>Done</Text>
  </TouchableOpacity>
);

const Dots = ({selected}) => {
  let backgroundColor = selected ? "rgba(37, 134, 113, 1)" : "rgba(185, 185, 185, 1)"

  return (
    <View 
      style={{
        width: 6,
        height: 6,
        borderRadius: 3,
        marginHorizontal: 3,
        backgroundColor
      }}
    />
  );
}

const OnboardScreen = ({ navigation }) => {
  // 标记引导已完成
  const markOnboardCompleted = async () => {
    try {
      await AsyncStorage.setItem('isFirstTimeOpen', 'false');
    } catch (e) {
      console.error('存储引导状态失败:', e);
    }
  };

  return (
    <>
      <Onboarding
        SkipButtonComponent={Skip}
        NextButtonComponent={Next}
        DoneButtonComponent={Done}
        DotComponent={Dots}
        onSkip={async () => {
          await markOnboardCompleted();
          navigation.replace("AuthScreen");
        }}
        onDone={async () => {
          await markOnboardCompleted();
          navigation.navigate("AuthScreen");
        }}
        titleStyles={{ color: 'blue' }}
        pages={[
          {
            backgroundColor: '#F2F2F2',
            image: <Image source={require('../../assets/images/onboard-5.png')} />,
            title: 'A.I. Powered',
            subtitle: 'Done with React Native Onboarding Swiper',
          },
          {
            backgroundColor: '#F2F2F2',
            image: <Image source={require('../../assets/images/onboard-5.png')} />,
            title: 'Onboarding 2',
            subtitle: 'Done with React Native Onboarding Swiper',
          },
          {
            backgroundColor: '#F2F2F2',
            image: <Image source={require('../../assets/images/onboard-5.png')} />,
            title: 'Onboarding 3',
            subtitle: 'Done with React Native Onboarding Swiper',
          },
          {
            backgroundColor: '#F2F2F2',
            image: <Image source={require('../../assets/images/onboard-5.png')} />,
            title: 'Onboarding 4',
            subtitle: 'Done with React Native Onboarding Swiper',
          },
        ]}
      />
    </>
  );
};
export default OnboardScreen

2. 优化App.tsx的判断逻辑

统一导航容器管理,添加异常处理避免逻辑卡顿:

import OnboardScreen from "./src/screens/OnboardScreen/OnboardScreen";
import AuthScreen from "./src/screens/AuthScreen/AuthScreen";
import { NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import AsyncStorage from '@react-native-async-storage/async-storage';
import { useEffect, useState } from "react";

const Stack = createNativeStackNavigator();

const App = () => {
  const [loading, setLoading] = useState(true);
  const [isFirstTimeLoad, setIsFirstTimeLoad] = useState(false) 
  
  const checkForFirstTimeLoaded = async () => {
    try {
      const result = await AsyncStorage.getItem('isFirstTimeOpen')
      setIsFirstTimeLoad(result === null);
    } catch (e) {
      console.error('读取引导状态失败:', e);
      setIsFirstTimeLoad(false);
    } finally {
      setLoading(false);
    }
  }

  useEffect(() => {
    checkForFirstTimeLoaded() 
  }, [])

  if(loading) return null
  
  return (
    <NavigationContainer>
      <Stack.Navigator screenOptions={{ headerShown: false }}>
        {isFirstTimeLoad ? (
          <Stack.Screen
            name="OnboardScreen"
            component={OnboardScreen}
          />
        ) : (
          <Stack.Screen
            name="AuthScreen"
            component={AuthScreen}
          />
        )}
      </Stack.Navigator>
    </NavigationContainer>
  );
}
export default App

说明

  • 用户点击Skip或Done时,会将isFirstTimeOpen存入AsyncStorage,下次启动App时读取到该值会直接进入AuthScreen
  • 添加try-catch处理AsyncStorage的读写异常,避免操作失败导致的逻辑异常
  • 统一导航容器结构,避免重复创建NavigationContainer

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 16:41:07