Redux更新时如何阻止组件重渲染?
如何阻止Redux中token更新时触发webview组件刷新?
看来你遇到的问题是:定时更新Redux中的token后,组件因为依赖refreshToken而重新渲染,导致<webview>的src被重新赋值,进而触发页面刷新。要解决这个问题,我们可以从切断组件渲染与token更新的关联,或者避免通过修改src来更新token这两个方向入手,以下是几种实用的解决方案:
方案一:手动更新webview的src(不触发组件重新渲染)
我们可以用useRef获取webview的实例,在组件初始化时设置一次src,之后仅在token更新时手动修改webview的src,而不是让组件整体重新渲染。这样既保证了webview能使用新token,又避免了不必要的组件刷新:
import { useRef, useEffect } from 'react'; import { useSelector, useDispatch } from 'react-redux'; const SampleComponent = () => { const webviewRef = useRef(null); const { refreshToken } = useSelector(state => state.auth); const dispatch = useDispatch(); // 初始化:设置初始src并启动定时任务 useEffect(() => { if (webviewRef.current) { webviewRef.current.src = `${HOSTNAME}/page/?refresh_token=${refreshToken}`; } // 启动每小时更新token的定时任务 window.tokensCron = new CronJob('0 0 * * *', () => { dispatch(getTokens()); }); // 组件卸载时清理定时任务 return () => { window.tokensCron?.stop(); }; }, []); // 空依赖数组,仅执行一次 // 当token更新时,手动修改webview的src useEffect(() => { if (webviewRef.current) { webviewRef.current.src = `${HOSTNAME}/page/?refresh_token=${refreshToken}`; } }, [refreshToken]); // 仅在refreshToken变化时执行 return <webview ref={webviewRef} />; }; export default SampleComponent;
方案二:完全阻止组件重新渲染(仅使用初始token)
如果你不需要webview在token更新后立即使用新token,只是想阻止组件刷新,那么可以用useMemo固定src的初始值,再配合React.memo阻止不必要的渲染:
import { useMemo, useEffect } from 'react'; import { useSelector } from 'react-redux'; const SampleComponent = () => { const { refreshToken } = useSelector(state => state.auth); // 仅在组件初始化时计算一次src const src = useMemo(() => { return `${HOSTNAME}/page/?refresh_token=${refreshToken}`; }, []); // 启动定时任务(保持不变) useEffect(() => { window.tokensCron = new CronJob('0 0 * * *', () => { store.dispatch(getTokens()); }); return () => { window.tokensCron?.stop(); }; }, []); return <webview src={src} />; }; // 使用React.memo阻止组件因无关状态变化而渲染 export default React.memo(SampleComponent);
注意:这种方式下,webview会一直使用初始的token,不会自动更新。如果需要webview使用新token,这个方案并不适用。
方案三:通过postMessage传递新token(最优解,无页面刷新)
如果你的目标是既让webview内部页面获取新token,又完全避免页面刷新,那最好的方式是用postMessage将新token传递给webview内部的页面,而不是修改src:
组件代码:
import { useRef, useEffect } from 'react'; import { useSelector, useDispatch } from 'react-redux'; const SampleComponent = () => { const webviewRef = useRef(null); const { refreshToken } = useSelector(state => state.auth); const dispatch = useDispatch(); // 初始化设置src并启动定时任务 useEffect(() => { if (webviewRef.current) { webviewRef.current.src = `${HOSTNAME}/page/?refresh_token=${refreshToken}`; } window.tokensCron = new CronJob('0 0 * * *', () => { dispatch(getTokens()); }); return () => { window.tokensCron?.stop(); }; }, []); // token更新时,发送消息给webview内部页面 useEffect(() => { if (webviewRef.current) { webviewRef.current.postMessage({ type: 'REFRESH_TOKEN', token: refreshToken }); } }, [refreshToken]); return <webview ref={webviewRef} />; }; export default SampleComponent;
webview内部页面代码:
// 在webview加载的页面中添加监听 window.addEventListener('message', (event) => { if (event.data?.type === 'REFRESH_TOKEN') { // 将新token存储到本地(比如localStorage)或全局状态 localStorage.setItem('refresh_token', event.data.token); // 后续发起请求时使用这个新token即可 } });
这种方式完全避免了webview的刷新,同时让内部页面能实时获取最新的token,是最推荐的方案。
内容的提问来源于stack exchange,提问作者Valerxx22
相关产品推荐
相关产品推荐

