我正在使用 Next.js 13、React 和 Redux 来管理状态。
我的目标是在服务器端加载初始数据并将其显示在客户端。我认为这将是 Redux 和 Next.js 的标准方法,但我还没有找到实现它的方法。
这是我的理解:
Redux 存储设置两次:一次在服务器端,另一次在客户端。我以为我可以简单地在服务器端获取数据,使用调度函数进行初始化,然后让客户端加载数据。但问题是服务器端组件无法使用调度或操作存储数据。
Redux 文档指出,React 服务器组件 (RSC) 不应读取或写入 Redux 存储,因为它们无法使用钩子或上下文,并且不意味着是有状态的。那么,我们如何加载初始数据呢?初始数据是否异常?如果是这样,我们如何更新这个初始数据?
这是我的代码,这是RSC
ContactListServerComponent.tsx
import ContactList from "@/component/Contacts/page"
import {
getInitialContactsData,
initializeContact,
} from "@/lib/features/contacts/contactSlice"
import { makeStore } from "@/lib/store"
import styles from "./contacts.module.scss"
const ContactListPage = async () => {
const initialData = await getInitialContactsData()
console.log("server component")
const store = makeStore()
store.dispatch(initializeContact(initialData))
return (
<div className={styles.container}>
<h1>Contacts</h1>
<ContactList />
</div>
)
}
export default ContactListPage
这是客户页面(联系人列表)
const ContactList = () => {
const dispatch = useAppDispatch()
const contacts = useSelector((state: RootState) => state.contacts)
const [filter, setFilter] = useState<string | null>(null)
useEffect(() => {
dispatch(getContacts())
}, [dispatch]
.... etc
我有一个服务器组件(ContactListServerComponent.tsx),我试图在其中获取和分派初始数据。然后,我有一个客户端组件 (ContactList),目前我正在使用
useEffect
来获取数据,这并没有充分利用 SSR 的优势。我不确定如何实现我的想法,以在服务器组件而不是客户端组件上获取初始数据。
我想知道如何从服务器组件上的 API 加载数据并将其传递给客户端组件。
有点晚了,但如果你想避免 prop 钻取,你可以简单地首先在页面或布局中加载初始数据,然后将其传递给客户端组件,该组件将获取初始数据并将其分派到客户端 redux 存储中:
'use client';
const InitialDataLoader = ({initialData}: any) => {
useEffect(() => {
store.dispatch(
actions.setState({key: 'initialData', value: initialData}),
);
}, []);
return null;
}
另一种选择是使用 React Context,例如:
interface ContextProps {initialData: any}
const InitialDataContext = createContext<ContextProps | undefined>(undefined);
export const InitialDataProvider = ({
children,
initialData,
}: {
children: ReactNode,
} & ContextProps) => {
return (
<InitialDataContext.Provider value={{initialData}}>
{children}
</InitialDataContext.Provider>
);
};
export const useInitialData = () => {
const context = useContext(InitialDataContext);
if (!context) {
throw new Error('useInitialData must be used within an InitialDataProvider');
}
return context.initialData;
};
然后在您要获取初始数据的服务器组件中使用它:
<InitialDataProvider initialData={initialData}>
{children}
</InitialDataProvider>
任何服务器端重新验证也会更改上下文中提供的数据。