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

React Native WebView的ref.injectJavascript在TabNavigator中始终为undefined

解决TabNavigator中WebView焦点监听时ref为undefined的问题

我之前也碰到过一模一样的情况,核心问题出在组件渲染/挂载时机和导航监听的绑定时机不匹配,再加上TabNavigator默认的懒加载特性,导致触发focus事件时WebView的ref还没被正确赋值,或者组件已经被卸载重建,ref引用丢失。

为什么之前的写法会失败?

  • 最初在空依赖的useEffect里绑定focus监听:此时组件刚初始化,WebView还没完成挂载,webViewRef.current自然是undefined;而且当Tab切换时,未激活的Tab组件会被卸载,切换回来时组件重新挂载,但监听已经绑定在旧的实例上了。
  • onLoadEnd里绑定监听:每次WebView加载完成都会绑定一次监听,会造成重复绑定,而且当Tab切换后再回来,WebView可能重新加载,这时候监听里的ref可能已经不是当前实例的引用。
  • useFocusEffect的写法:没有先检查webViewRef.current是否存在,而且依赖了props.navigation,但ref的变化不会触发依赖更新,导致监听里的ref还是旧的引用。

而setTimeout能工作的原因很简单:延迟执行给了WebView足够的挂载时间,此时webViewRef.current已经指向了WebView实例。

正确的解决方案

这里提供两种经过验证的写法,都能解决ref为undefined的问题:

方案1:使用useFocusEffect(推荐,React Navigation官方推荐的焦点监听方式)

import React, { useRef } from 'react';
import { WebView } from 'react-native-webview';
import { useFocusEffect } from '@react-navigation/native';

export default (props) => {
  const webViewRef = useRef(null);

  useFocusEffect(
    React.useCallback(() => {
      // 关键:先检查ref是否存在,避免报错
      if (webViewRef.current) {
        // 注意injectJavaScript需要返回true,这是WebView的要求
        const injectCode = `
          console.log("Tab获得焦点,注入JS成功!");
          document.body.style.backgroundColor = 'lightgreen';
          true;
        `;
        webViewRef.current.injectJavaScript(injectCode);
      }

      // 可选:返回清理函数,在Tab失焦时执行(比如恢复页面状态)
      return () => {
        if (webViewRef.current) {
          webViewRef.current.injectJavaScript(`
            document.body.style.backgroundColor = 'white';
            true;
          `);
        }
      };
    }, [])
  );

  return (
    <WebView 
      ref={webViewRef} 
      source={{ uri: 'https://github.com/react-native-community/react-native-webview' }}
      // 确保启用JavaScript,否则注入代码无效
      javaScriptEnabled={true}
    />
  );
};

方案2:使用navigation.addListener配合正确的useEffect依赖

import React, { useRef, useEffect } from 'react';
import { WebView } from 'react-native-webview';

export default (props) => {
  const webViewRef = useRef(null);

  useEffect(() => {
    const unsubscribe = props.navigation.addListener('focus', () => {
      if (webViewRef.current) {
        const injectCode = `
          console.log("Tab获焦,注入JS");
          true;
        `;
        webViewRef.current.injectJavaScript(injectCode);
      }
    });

    // 组件卸载时取消监听,避免内存泄漏
    return unsubscribe;
  }, [props.navigation]); // 依赖navigation,确保每次导航上下文变化时重新绑定监听

  return (
    <WebView 
      ref={webViewRef} 
      source={{ uri: 'https://github.com/react-native-community/react-native-webview' }}
      javaScriptEnabled={true}
    />
  );
};

额外注意事项

  • 确保WebView开启了javaScriptEnabled={true},否则注入的代码不会执行。
  • injectJavaScript方法的代码最后必须返回true,这是react-native-webview的要求,否则可能会出现奇怪的问题。
  • 如果你的TabNavigator开启了lazy={false}(默认是true),组件不会被卸载,这时候ref的问题会少一些,但还是建议保留ref存在性检查,避免意外情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 07:12:49