在使用next.js 我们有一部分数据,是需要同步到服务端环境的,在页面到达浏览器之前,redux就应该填充一部分数据
其他框架参考, nuxt.js vuex 某个只在服务端初始化执行的action函数
首先建立仓库文件 store/index.js
import { combineReducers, createStore } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension/developmentOnly';
import user from './reducers/user'
import config from './reducers/config'
import anchor from './reducers/anchor';
import router from './reducers/router';
//每个redux已经单独分开,如果在初始化需要单独初始化某个模块的数据,需要这样合并,详情看redux文档
const combined = (state = {}, action) => {
return {
user: user(state?.user, action),
config: config(state?.config, action),
router: router(state?.router, action),
anchor: anchor(state?.anchor, action)
};
}
//这里为了在服务端创建时,初始化一遍redux
const createNextStore = (init) => createStore(combined, init, composeWithDevTools());
export default createNextStore
建立withRedux 用于结合redux和app
import createNextStore from "./index";
import { getUserInfo, getAnchorPage } from '@/service/live';
import dayJs from 'dayjs';
import React from 'react'
const __NEXT_REDUX_STORE = "__NEXT_REDUX_STORE"; //定义个变量用来查看客户端是否存在store
//根据不同场景进行创建或者返回现有store
function getOrCreateStore (initialState) {
const isServer = typeof window === "undefined";
if (isServer) {
// 服务端
// 返回新的store
return createNextStore(initialState);
}
if (!window[__NEXT_REDUX_STORE]) {
// console.log('XXX')
// 是客户端客户端没有store create
window[__NEXT_REDUX_STORE] = createNextStore(initialState);
}
return window[__NEXT_REDUX_STORE];
}
const withRedux = (Comp) => {
// 高阶组件,让每个app都经历高阶组件进行处理集成redux
return class HocReducerComp extends React.Component {
constructor(props) {
super(props);
this.ReduxStore = getOrCreateStore(props.initialState);
}
static async getInitialProps (ctx) {
let user = {
}
let anchor = {
}
//尝试在服务端先获取用户信息,在注入到客户端
try {
//尝试获取用户信息
if (ctx.ctx.req?.cookies['app-access-token']) {
const code = ctx.ctx.req.cookies['app-access-token'] || ""
user.info = await getUserInfo({
headers: {
"app-access-token": code
}
})
user.info['app_access_token'] = code
user.info = { ...user?.info, registerDay: dayJs().diff(dayJs(user?.info?.createTime), 'day') || 0, }
if (user?.info?.roomId) {
const c = await getAnchorPage({
headers: {
"app-access-token": code
}
})
const { host = {}, ...other } = c;
anchor.anchorInfo = { ...host, ...other }
}
}
} catch (error) {
console.log(error)
}
const MyStore = getOrCreateStore({ anchor, user });
/* 利用ctx把store传入App,在App中进行store的初始化 */
ctx.ReduxStore = MyStore;
let appProps = {};
if (typeof Comp.getInitialProps === 'function') {
appProps = await Comp.getInitialProps(ctx);
}
// 这里都是在服务端重新注入数据
return { ...appProps, initialState: MyStore.getState() };
}
render () {
return <Comp {...this.props} ReduxStore={this.ReduxStore} />;
}
}
};
export default withRedux;
_app.js 合并
import 'normalize.css';
import '../styles/main.scss';
import { Provider } from "react-redux";
import withRedux from "@/store/withRedux"
import App from 'next/app'
function nextApp ({ Component, pageProps, ReduxStore }) {
return (
<Provider store={ReduxStore}>
<Component {...pageProps} />
</Provider>
)
}
nextApp.getInitialProps = async (ctx) => {
const appProps = await App.getInitialProps(ctx);
//ctx.ReduxStore
return { ...appProps };
};
export default withRedux(nextApp)