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

React Chrome扩展:如何在ContentScript中获取已登录currentUser?

问题原因

Chrome扩展的Popup和ContentScript是完全独立的执行上下文,各自的React应用(包括AuthContext)相互隔离,Firebase Auth的登录状态也不会自动在这两个环境之间同步。你在Popup里的AuthContext仅作用于Popup的React树,ContentScript里的AuthContext是全新的实例,自然监听不到Popup的登录状态。

解决方案

方案一:用Chrome Storage API共享用户信息

这是最简单直接的方式,通过Chrome的本地存储同步用户登录状态。

步骤1:在Popup中存储用户ID

修改Popup里的AuthContext.js,登录成功后将用户ID存入Chrome本地存储:

// AuthContext.js
export function AuthProvider({ children }) {
    const [currentUser, setCurrentUser] = useState();
    const [loading, setLoading] = useState(true);
    
    useEffect(() => {
        const unsubscribe = onAuthStateChanged(auth, (user) => {
            setCurrentUser(user);
            setLoading(false);
            // 同步用户信息到Chrome存储
            if (user) {
                chrome.storage.local.set({ currentUserId: user.uid });
            } else {
                chrome.storage.local.remove('currentUserId');
            }
        });
        return unsubscribe;
    }, []); 
    
    const value = { currentUser };

    return (
        <AuthContext.Provider value={value}>
            {!loading && children}
        </AuthContext.Provider>
    );
}

步骤2:在ContentScript中读取并监听用户ID

修改ContentScript的Page组件,从Chrome存储获取用户ID并监听变化:

// ContentScript.js
export default function Page() {
  const [currentUserId, setCurrentUserId] = useState(null);

  useEffect(() => {
    // 初始化获取存储的用户ID
    chrome.storage.local.get('currentUserId', (result) => {
      result.currentUserId && setCurrentUserId(result.currentUserId);
    });

    // 监听存储变化,实时更新用户状态
    const handleStorageChange = (changes, area) => {
      if (area === 'local' && changes.currentUserId) {
        setCurrentUserId(changes.currentUserId.newValue);
      }
    };
    chrome.storage.onChanged.addListener(handleStorageChange);

    // 组件卸载时清理监听
    return () => {
      chrome.storage.onChanged.removeListener(handleStorageChange);
    };
  }, []);

  console.log("Current user ID: ", currentUserId);
  
  return <div></div>;
}

步骤3:添加存储权限

在manifest.json中声明storage权限:

{
  "permissions": ["storage"]
}

方案二:用Chrome消息传递同步状态

如果需要更实时的状态同步或传递更多用户信息,可以用Chrome的消息传递机制。

步骤1:新增Background脚本维护状态

创建background.js,作为Popup和ContentScript的中间层:

// background.js
// 监听Popup的状态更新请求
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.type === 'UPDATE_USER') {
    chrome.storage.local.set({ currentUser: message.user });
    sendResponse({ success: true });
  } 
  // 监听ContentScript的用户信息请求
  else if (message.type === 'GET_USER') {
    chrome.storage.local.get('currentUser', (result) => {
      sendResponse(result.currentUser);
    });
    return true; // 异步响应需返回true
  }
});

步骤2:Popup登录后通知Background

修改Popup的AuthContext.js,登录成功后发送消息到Background:

// AuthContext.js
useEffect(() => {
  const unsubscribe = onAuthStateChanged(auth, (user) => {
    setCurrentUser(user);
    setLoading(false);
    // 发送用户状态到Background
    chrome.runtime.sendMessage({
      type: 'UPDATE_USER',
      user: user ? { uid: user.uid, email: user.email } : null
    });
  });
  return unsubscribe;
}, []);

步骤3:ContentScript请求用户信息

修改ContentScript的Page组件,主动请求并监听用户状态:

// ContentScript.js
export default function Page() {
  const [currentUser, setCurrentUser] = useState(null);

  useEffect(() => {
    // 初始化请求用户信息
    chrome.runtime.sendMessage({ type: 'GET_USER' }, (user) => {
      setCurrentUser(user);
    });

    // 监听Background的状态更新通知
    const handleMessage = (message) => {
      if (message.type === 'UPDATE_USER') {
        setCurrentUser(message.user);
      }
    };
    chrome.runtime.onMessage.addListener(handleMessage);

    return () => {
      chrome.runtime.onMessage.removeListener(handleMessage);
    };
  }, []);

  console.log("Current user: ", currentUser?.uid);
  
  return <div></div>;
}

步骤4:注册Background脚本

在manifest.json中添加Background脚本声明:

{
  "background": {
    "service_worker": "background.js"
  }
}
额外修正:AuthContext的loading状态问题

原代码中AuthContext.js未定义loading变量,导致{!loading && children}逻辑报错,需补充初始化:

// AuthContext.js
export function AuthProvider({ children }) {
    const [currentUser, setCurrentUser] = useState();
    const [loading, setLoading] = useState(true); // 新增loading状态
    
    useEffect(() => {
        const unsubscribe = onAuthStateChanged(auth, (user) => {
            setCurrentUser(user);
            setLoading(false); // 获取状态后结束loading
        });
        return unsubscribe;
    }, []); 
    
    const value = { currentUser };

    return (
        <AuthContext.Provider value={value}>
            {!loading && children}
        </AuthContext.Provider>
    );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 17:33:25