我正在使用reactn
来管理我的全局状态,而不是直接使用redux。我有一个SSR react应用,但是在使全局状态正常工作时遇到了一些问题。据我了解,我应该使用它们的Provider
组件(https://github.com/CharlesStover/reactn/blob/master/Provider.md)。总体而言,我正在服务器和客户端上创建一个新的Provider,然后在我的每个React组件中使用相同的Provider组件。
我有两个主要问题:
setGlobal()
时组件没有更新。在我的组件之一中,我有export default StateManager.Provider.withGlobal(
({ loggedIn, currentUser, signInError }: Partial<State>) => ({
currentUser,
signInError
})
)(UserSignInPage);
然后,当用户登录时,我会拨打以下电话:
StateManager.Provider.setGlobal({
loggedIn: true,
currentUser: res.user,
});
以下是我的提供商,服务器和客户端代码的精简版:
// StateManager.ts
export default class StateManger {
static reducers: Reducers = {
addCardToBeComposed
};
static defaultState: State = {
device: DeviceType.MOBILE,
currentUser: null,
loggedIn: false
};
static Provider: any = createProvider(
StateManger.defaultState,
StateManger.reducers
);
static getState(): State {
try {
const serializedState: string = Cookies.get('appState');
return JSON.parse(serializedState) || StateManger.defaultState;
} catch (err) {
console.warn('Error trying to getState', err);
}
}
static saveState(state: State): void {
try {
const serializedState: string = JSON.stringify(state);
Cookies.set('appState', serializedState);
} catch (err) {
console.warn('Error saving state data', err, state);
}
}
static createProvider(state: State): ReactNProvider {
StateManger.Provider = createProvider(state, StateManger.reducers);
return StateManger.Provider;
}
}
Server.ts
const styledComponentsSheet = new ServerStyleSheet();
const materialSheets = new ServerStyleSheets();
const context: any = {};
const cookieAppState = req.cookies.appState;
const appStateObj = JSON.parse(cookieAppState);
const appState: any = {
...StateManager.defaultState,
appStateObj
};
StateManager.createProvider(appState);
const markup: string = renderToString(
styledComponentsSheet.collectStyles(
materialSheets.collect(
<StaticRouter context={context} location={req.url}>
<StateManager.Provider>
<App />
</StateManager.Provider>
</StaticRouter>
)
)
);
const materialSheet = renderToString(materialSheets.getStyleElement());
const sheet = styledComponentsSheet.getStyleElement();
const styleSheet: string = renderToString(<>{sheet}</>);
res.send(`<html lang="en" dir="ltr">
<head>
<meta charSet="utf-8" />
<meta
name="viewport"
content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no"
/>
<meta
name="theme-color"
content={theme.palette.primary.main}
/>
<script>__APP_DATA__ = ${JSON.stringify(appState)}</script>
${materialSheet}
${styleSheet}
${
process.env.NODE_ENV === 'production'
? `<script src="${assets.client.js}" defer></script>`
: `<script src="${assets.client.js}" defer crossorigin></script>`
}
</head>
<body>
<div id="root">${markup}</div>
</body>
</html>
`);
...
Client.tsx
let Provider = StateManager.createProvider(StateManager.getState());
try {
Provider = StateManager.createProvider(window.__APP_DATA__);
} catch (e) {
console.warn('Error tryingt to parse app data from server', e);
}
hydrate(
<BrowserRouter>
<Provider>
<App />
</Provider>
</BrowserRouter>,
document.getElementById('root')
);