redux RSC可以用存储值更新吗?

nue99wik  于 2023-08-05  发布在  其他
关注(0)|答案(2)|浏览(89)

我有一个React服务器组件,它可以访问初始值,甚至可以将操作分派到redux存储中
初始值被设置为10

// store/counterSlice.ts
const initialState: CounterState = {
  value: 10,
};

// app/serverComponent.tsx
export default async function ServerComponent() {
  const data = await fetchSomeData();
  store.dispatch(updateTestData(data)); // this works

  const counter = store.getState().counter; // this works - gets the initial value of 10

  console.log('this log is shown in the server');

  return (
    <main className={styles.main}>
      <div className={styles.description}>
        {/* shows the initial value of 10 */}
        <p>Current Count: {counter.value}</p>
      </div>
    </main>
  );
}

字符串
我知道服务器组件可以在Nextjs中使用router.refresh()重新呈现

// 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());
    // this rerenders the server component
    router.refresh();
  };

  return (
    <div id='with-font-container'>
      {/* this value us correctly subscribed and updated to the store changes */}
      <p>Current Count: {count}</p>
      <button onClick={handleIncrementCounter}>Increment Count</button>
      {children}
    </div>
  );
}


两个组件都位于同一页面中,并且增量计数成功地增加了客户端中的计数,但是服务器组件保持初始值10,尽管router.refresh()成功地重新呈现(由服务器中的console.log确认)

// app/page.tsx
export default function Home() {
  return (
    <div className='bg-black text-3xl'>
      <ClientComponent>
        {/* this error is a known next13 bug https://github.com/vercel/next.js/issues/42292 */}
        {/* @ts-expect-error Server Component */}
        <ServerComponent />
      </ClientComponent>
    </div>
  );
}


这意味着RSC将永远无法访问 updated redux存储(或任何其他全局存储),对吗?
这是code,以防你好奇

ws51t4hk

ws51t4hk1#

是的,我相信因为RSC存在于服务器上,它的redux示例在服务器端是活动的,并且永远不会被运行在最终用户浏览器中的完全独立的redux示例更新。RSC不应该/不允许useEffectuseState。如果你在ServerComponent中使用了react-redux中的useDispatch,这是你应该使用Redux的方式,而不是像在那里那样直接导入商店,那么构建就会失败,因为useStore/useDispatch调用了useEffect和/或useState。
我希望在另一个答案中看到的是有人演示如何从根本上实现OP试图实现的目标:在服务器上获取一些数据,然后在数据源更新时让RSC重新呈现。
在RSC文档中,它提到RSC的刷新序列快乐路径需要由框架实现。因此,Next.js和Remix会对这个问题给出具体的答案。如果能看到一个答案,详细说明在Next.js和Remix中是如何做到这一点的,那就太好了。

pbossiut

pbossiut2#

问题是服务器存储和客户端存储不同步。route.refresh正在重新呈现,将服务器组件和客户端组件发送到客户端。但是当你在客户端时,当你点击increment来更新redux商店时,那个服务器组件已经在服务器上呈现了,它不能访问客户端代码或客户端商店。
如果您在pages目录中使用next-redux-wrapper包设置redux,则在切片中设置了hydrate操作

extraReducers: {
    [HYDRATE]: (state, action) => {
      return {
        ...state,
        ...action.payload.value,
      };
    },

字符串
getServerSideProps中,我们获取数据,填充存储并将此存储发送到客户端,然后客户端使用服务器存储数据创建新存储。在本例中,我们向客户端发送一个已经获取并填充的存储,客户端可以访问它。
但在您的示例中,每次在服务器组件上调用store.getState().counter时,您都希望从存储在Provider中的客户端存储中读取数据,而访问此Provider的唯一方法是从客户端使用useSelector钩子

相关问题