React Server Component能否通过全局存储值更新?
我有一个React Server Component(RSC),它可以访问Redux存储的初始值,甚至能向Redux存储分发action,初始值设为10。我知道在Next.js中可通过router.refresh()重渲染RSC,客户端组件点击按钮能成功递增计数,但RSC在重渲染后仍显示初始值10。请问RSC是否永远无法访问更新后的全局存储(如Redux)?
相关代码
store/counterSlice.ts
const initialState: CounterState = { value: 10, };
app/serverComponent.tsx
export default async function ServerComponent() { const data = await fetchSomeData(); store.dispatch(updateTestData(data)); // 此代码可正常运行 const counter = store.getState().counter; // 可获取初始值10 console.log('this log is shown in the server'); return ( <main className={styles.main}> <div className={styles.description}> {/* 显示初始值10 */} <p>Current Count: {counter.value}</p> </div> </main> ); }
app/clientComponent.tsx
'use client'; import { useDispatch, useSelector } from 'react-redux'; import { AppDispatch, RootState } from '@/store'; import { increment } from '@/store/counterSlice'; import { useRouter } from 'next/navigation'; export default function ClientComponent({ children, }: { children: React.ReactNode; }) { const dispatch = useDispatch<AppDispatch>(); const count = useSelector((state: RootState) => state.counter.value); const router = useRouter(); const handleIncrementCounter = () => { dispatch(increment()); // 重渲染服务端组件 router.refresh(); }; return ( <div id='with-font-container'> {/* 此值可正确订阅并随存储变化更新 */} <p>Current Count: {count}</p> <button onClick={handleIncrementCounter}>Increment Count</button> {children} </div> ); }
app/page.tsx
export default function Home() { return ( <div className='bg-black text-3xl'> <ClientComponent> {/* 此错误为Next13已知bug */} {/* @ts-expect-error Server Component */} <ServerComponent /> </ClientComponent> </div> ); }
解答
不是“永远无法访问”,但你的代码里出现这种情况是核心机制导致的:
服务端与客户端Redux实例完全隔离:服务端每次渲染RSC时,使用的是服务端环境的Redux存储实例,和客户端浏览器里的Redux存储是完全独立的两个环境。客户端点击按钮dispatch的
incrementaction,只会修改客户端的存储状态,服务端的存储始终保持初始值10。router.refresh()触发的是服务端重新渲染RSC,自然读取的还是服务端存储的初始值。router.refresh()不同步客户端状态到服务端:这个方法的作用是让服务端重新生成当前页面的HTML并发送到客户端,但它不会把客户端的Redux状态传递给服务端,服务端也没有自动同步客户端状态的机制。
可行的解决思路
将状态持久化到服务端存储:客户端dispatch action时,同时调用API把最新状态保存到数据库、Redis等服务端可访问的存储中。RSC重渲染时,通过
fetch或直接读取服务端存储获取最新值,而不是依赖服务端的Redux实例。通过客户端组件传递状态:如果不需要服务端渲染最新状态,可以让客户端组件把更新后的count作为props传递给RSC。但注意这种情况下,RSC的内容实际是由客户端控制展示的,并非服务端渲染的最新状态。
拆分职责:让Redux只负责客户端的状态管理,RSC所需的状态直接从数据源(如API)获取,不依赖全局Redux存储。
内容的提问来源于stack exchange,提问作者Fer Toasted

