如何使用 Angular 17 和 SSR 来滋润 ngrx 存储

问题描述 投票:0回答:1

我有一个使用服务器端渲染的 Angular 17 应用程序。应用程序的状态是使用 ngrx 进行管理的。

当我访问该页面时,我可以看到该页面是预先渲染的(例如,通过查看页面的源代码),但是一旦页面加载,Angular 似乎就从头开始。

例如,我有一些通过HTTP请求获取的标签。最初我在页面中看到标签,但随后 Angular 启动并清除状态,将标签呈现为空白。然后,它执行 HTTP 请求来获取这些标签并再次显示它们。最终结果是正确的,但是当 Angular 接管时会出现闪烁。根据我的阅读,它应该重用服务器的状态。

在浏览器控制台上,我可以看到以下内容:

Angular hydrated 12 component(s) and 98 node(s), 0 component(s) were skipped. Learn more at https://angular.io/guide/hydration.

这似乎表明 Angular 能够水合我的所有组件。我有 Redux 开发工具,通过检查它们,似乎是存储没有被水合,因为初始状态对应于存储的默认状态,而我希望它从来自服务器。

我需要做什么来保持商店的状态?

angular ngrx ngrx-store angular17 angular17-ssr
1个回答
0
投票

我找到了以下解决方案。我在

provideStore
调用中注册了一个元减速器。当在服务器上调用时,它会捕获商店的状态并将其添加到
TransferState
。在客户端,它拦截
INIT
操作并恢复存储在传输状态中的状态。

说明

顾名思义,

TransferState
允许在服务器和客户端之间传输数据。例如,Angular 使用它来将 HTTP 缓存传输到客户端。

元减速器是一个可以包装现有减速器的函数,为您提供一个可以拦截存储中发生的所有操作的点。

通过利用这两种机制,我们能够添加我们希望在客户端中立即可用的商店部分。请注意,您可能不想传输整个存储,因为由于 Angular 已经传输了 HTTP 缓存,因此服务器上请求的任何可缓存数据也将立即可供客户端使用。

示例

provideStore({
    router: routerReducer,
}, {
    metaReducers: [
        reducer => {
            const storeStateKey = makeStateKey<string>("storeState");
            const platformId = inject(PLATFORM_ID);
            const transferState = inject(TransferState);

            if (isPlatformServer(platformId)) {
                let lastState: any = {};
                transferState.set(storeStateKey, lastState);

                // Only include the keys that are useful to access immediately
                transferState.onSerialize<any>(storeStateKey, () => ({
                    app: lastState["app"],
                    topMenu: lastState["topMenu"],
                    localization: lastState["localization"]
                }));

                return (state, action) => {
                    lastState = reducer(state, action);
                    return lastState;
                };
            } else {
                return (state, action) => {
                    const next = reducer(state, action);
                    if (action.type === INIT) {
                        const initialState = transferState.get<any>(storeStateKey, {});
                        return { ...next, ...initialState };
                    }
                    return next;
                };
            }
        }
    ]
}),
© www.soinside.com 2019 - 2024. All rights reserved.