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

返回重进页面时目标useEffect未执行的问题排查与解决

问题解决:返回后重新进入页面时广告加载逻辑不执行

问题根源

  1. 插屏广告实例interstitial在组件外部创建为单例,页面销毁后实例状态残留,重新进入时无法正常初始化加载
  2. 依赖navigation的普通useEffect不会在页面重新聚焦时触发(navigation对象未发生变化)
  3. 未将页面聚焦状态与广告加载逻辑绑定,导致返回后进入页面时广告加载逻辑不执行

修复后的完整代码

import { useRoute, useIsFocused, useFocusEffect } from '@react-navigation/native'
import React, { useEffect, useState, useRef } from 'react';
import { View, Text, BackHandler } from 'react-native';
import { InterstitialAd, AdEventType, TestIds } from 'react-native-google-mobile-ads';
import { incrementCounter, resetCounter } from '../store/counter';
import { useSelector, useDispatch } from 'react-redux';
import NetInfo from '@react-native-community/netinfo';
import { gql, useQuery } from '@apollo/client';

const QUERY = gql `
  //some query
`

function AdScreen({navigation}) {
  const [isConnected, setIsConnected] = useState(true);
  const [loaded, setLoaded] = useState(false);
  const isFocused = useIsFocused();
  const dispatch = useDispatch();
  const counter = useSelector(state => state.counter.count);
  const interstitialRef = useRef(null); // 用ref保存广告实例

  const { 
    params: { title, id },
  } = useRoute();

  const {data, loading, error, refetch} = useQuery(QUERY, {
    variables: {id},
    fetchPolicy: 'cache-and-network',
  });

  useEffect(() => {
    const unsubscribe = NetInfo.addEventListener(state => {
      setIsConnected(state.isConnected);
    });
    return () => unsubscribe();
  }, []);

  const handleRefresh = () => refetch();

  // 替换原THIS SECTION的逻辑,改用useFocusEffect
  useFocusEffect(
    React.useCallback(() => {
      // 初始化广告实例
      interstitialRef.current = InterstitialAd.createForAdRequest(TestIds.INTERSTITIAL);
      
      const unsubscribe = interstitialRef.current.addAdEventListener(
        AdEventType.LOADED,
        () => setLoaded(true)
      );

      // 加载广告
      interstitialRef.current.load();

      // 页面失焦时清理
      return () => {
        unsubscribe();
        // 销毁广告实例避免内存泄漏
        if (interstitialRef.current) {
          interstitialRef.current.destroy();
        }
      };
    }, [])
  );

  useEffect(() => {
    const backHandler = BackHandler.addEventListener('hardwareBackPress', handleBackPress);
    return () => backHandler.remove();
  }, []);

  useEffect(() => {
    // 计数达标且广告已加载时展示
    if (counter >= 5 && loaded && interstitialRef.current) {
      interstitialRef.current.show();
      setLoaded(false);
      // 展示后重新加载下一次广告
      interstitialRef.current.load();
      dispatch(resetCounter());
    }
  }, [counter, loaded]);

  const handleBackPress = () => {
    dispatch(incrementCounter());
    return true;
  };

  return (
    <View style={{flex:1, justifyContent:'center', alignItems:'center'}}>
      <Text>
        计数:{counter} | 广告加载状态:{loaded ? '已加载' : '未加载'} | 页面聚焦状态:{isFocused ? '已聚焦' : '未聚焦'}
      </Text>           
    </View>
  )
}

export default AdScreen

关键改动说明

  • 广告实例管理:用useRef在组件内部保存广告实例,每次页面聚焦时重新创建,避免单例状态残留
  • useFocusEffect替代useEffect:确保每次页面进入(包括返回后)都执行广告初始化和加载逻辑,useFocusEffect会在页面聚焦时触发,失焦时执行清理
  • 实例销毁:在页面失焦时调用destroy()销毁广告实例,避免内存泄漏
  • 逻辑简化:移除不必要的isFocused依赖,广告展示逻辑仅依赖计数和加载状态

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 15:47:31