React修改Cookie后组件未自动重渲染问题求助
核心问题拆解
- 组件不自动重渲染:
useCookies(['userCookies'])仅监听了userCookies,但实际业务用到的是analyticsCookie和necessaryCookie,导致这类cookie变化时无法触发组件更新;另外Footer组件的本地state没有同步props中cookies的最新值。 - GA持续运行:删除GA相关cookie只是清除了浏览器存储,但已经初始化的GA实例仍在内存中继续发送请求,需要手动禁用跟踪行为。
分步解决方案
1. 让react-cookie监听目标cookie
修改App.js里的useCookies调用,把需要实时监听的cookie全部加入数组,这样当这些cookie变化时,App组件会自动重渲染,子组件能拿到最新的cookies数据:
// App.js const [cookies, setCookie, removeCookie] = useCookies(['analyticsCookie', 'necessaryCookie']);
2. 同步Footer组件的本地state
Footer里的checkedAnalytics和necessaryConsent是本地state,初始值来自props的cookies,但props更新时不会自动同步。添加useEffect监听props的cookies变化,实时更新本地state:
// Footer.js React.useEffect(() => { setCheckedAnalytics(!!cookies.analyticsCookie); setNecessaryConsent(!!cookies.necessaryCookie); }, [cookies]); // 当cookies对象变化时触发同步
3. 停止GA的跟踪行为
当用户关闭分析类cookie时,除了删除GA的相关cookie,还要禁用GA的发送任务,阻止它继续上报数据:
// Footer.js中处理关闭分析的逻辑里添加: if (cookies.analyticsCookie) { functionSetCookie('analyticsCookie', false, {path: '/', expires: dateExpire, sameSite: 'none', secure: true}); functionRemoveCookie('_ga'); functionRemoveCookie('_gat'); functionRemoveCookie('_gid'); // 停止GA发送数据 if (window.ga) { window.ga('set', 'sendHitTask', null); } }
后续用户重新开启分析权限时,再重新初始化GA即可恢复跟踪。
修改后的完整代码示例
App.js
export default function App() { // 监听业务需要的cookie const [cookies, setCookie, removeCookie] = useCookies(['analyticsCookie', 'necessaryCookie']); const [blockScroll, allowScroll] = useScrollBlock(); AOS.init(); const [isOpen, setIsOpen] = useState(false); const toggle = () => { setIsOpen(!isOpen); isOpen ? allowScroll() : blockScroll(); } const functionSetCookie = (name, boolean, options) => { setCookie(name, boolean, options); } const functionRemoveCookie = (name) => { removeCookie(name); } return ( <main className="text-gray-400 bg-gray-900 body-font"> <Navbar toggle={toggle} cookies={cookies}/> <Sidebar isOpen={isOpen} toggle={toggle}/> <About /> <Timeline /> <Projects /> <Skills /> <Contact /> <Footer cookies={cookies} functionSetCookie={functionSetCookie} functionRemoveCookie={functionRemoveCookie} /> </main> ); }
Footer.js
export default function Footer ({cookies, functionSetCookie, functionRemoveCookie}) { const [checkedAnalytics, setCheckedAnalytics] = React.useState(!!cookies.analyticsCookie); const [necessaryConsent, setNecessaryConsent] = React.useState(!!cookies.necessaryCookie); // 同步props中cookies的变化 React.useEffect(() => { setCheckedAnalytics(!!cookies.analyticsCookie); setNecessaryConsent(!!cookies.necessaryCookie); }, [cookies]); return ( <FooterContainer> <div className='cookieBannerContainer' style={{display: showBannerCookie, opacity: opacityBannerCookie, transition: 'opacity 0.3s ease'}}> <div className="bannerRightColumn"> <button style={{transition: "0.2s ease-in-out", padding: "5px 10px", margin: "15px", marginBottom:"5px", justifyContent: "center"}} onClick={() => { if (!necessaryConsent) { functionSetCookie('necessaryCookie', true, {path: '/', expires: dateExpire, sameSite: 'none', secure: true}); setNecessaryConsent(true); } if (!cookies.analyticsCookie){ functionSetCookie('analyticsCookie', true, {path: '/', expires: dateExpire, sameSite: 'none', secure: true}); setCheckedAnalytics(true); ReactGA.initialize("XXXXXXXXXX", {debug: true}); ReactGA.pageview("pageview") } if (!checkedAnalytics){ setCheckedAnalytics(true); } setOpacityBannerCookie(0); setTimeout(() => setShowBannerCookie("none"), 300 ) }} className="inline-flex text-white bg-green-500 border-0 py-2 px-6 focus:outline-none hover:bg-green-600 rounded text-lg"> 接受所有cookie </button> <button style={{transition: "0.2s ease-in-out", padding: "5px 10px", margin: "15px", marginBottom:"5px", marginTop:"10px", justifyContent: "center"}} onClick={() => { if (!necessaryConsent) { functionSetCookie('necessaryCookie', true, {path: '/', expires: dateExpire, sameSite: 'none', secure: true}); setNecessaryConsent(true); } if (checkedAnalytics) { if (!cookies.analyticsCookie) { functionSetCookie('analyticsCookie', true, {path: '/', expires: dateExpire, sameSite: 'none', secure: true}); ReactGA.initialize("XXXXXXX", {debug: true}); ReactGA.pageview("pageview") } } else { if (cookies.analyticsCookie) { functionSetCookie('analyticsCookie', false, {path: '/', expires: dateExpire, sameSite: 'none', secure: true}); functionRemoveCookie('_ga'); functionRemoveCookie('_gat'); functionRemoveCookie('_gid'); // 停止GA跟踪 if (window.ga) { window.ga('set', 'sendHitTask', null); } } } setOpacityBannerCookie(0); setTimeout(() => setShowBannerCookie("none"), 300 ) }} className="ml-4 inline-flex text-gray-400 bg-gray-800 border-0 py-2 px-6 focus:outline-none hover:bg-gray-700 hover:text-white rounded text-lg"> 接受选中的cookie </button> <button style={{transition: "0.2s ease-in-out", padding: "5px", margin: "15px", marginTop:"10px", justifyContent: "center", paddingLeft: "10px", paddingRight: "10px"}} onClick={() => { if (!necessaryConsent) { functionSetCookie('necessaryCookie', true, {path: '/', expires: dateExpire, sameSite: 'none', secure: true}); setNecessaryConsent(true); } if (cookies.analyticsCookie) { functionSetCookie('analyticsCookie', false, {path: '/', expires: dateExpire, sameSite: 'none', secure: true}); functionRemoveCookie('_ga'); functionRemoveCookie('_gat'); functionRemoveCookie('_gid'); // 停止GA跟踪 if (window.ga) { window.ga('set', 'sendHitTask', null); } } if (checkedAnalytics) { setCheckedAnalytics(false); } setOpacityBannerCookie(0); setTimeout(() => setShowBannerCookie("none"), 300 ) }} className="ml-4 inline-flex text-gray-400 bg-gray-800 border-0 py-2 px-6 focus:outline-none hover:bg-gray-700 hover:text-white rounded text-lg"> 仅接受必要cookie </button> </div> </div> </FooterContainer> ) }
内容的提问来源于stack exchange,提问作者BlowLore
相关产品推荐
相关产品推荐

