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
相关产品推荐
相关产品推荐

