diff --git a/package.json b/package.json index 5d19528..45a778a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-ssr", - "version": "1.2.9", + "version": "1.3.0", "author": "mrwang", "license": "MIT", "scripts": { @@ -15,60 +15,60 @@ "test": "jest" }, "dependencies": { - "@chakra-ui/react": "^1.8.7", + "@chakra-ui/react": "^1.8.8", "@emotion/react": "^11.9.0", "@emotion/server": "^11.4.0", "@emotion/styled": "^11.8.1", "@loadable/component": "^5.15.2", "@loadable/server": "^5.15.2", - "@mui/material": "^5.6.2", - "antd": "^4.19.5", - "axios": "^0.26.1", + "@mui/material": "^5.8.0", + "antd": "^4.20.4", + "axios": "^0.27.2", "chalk": "4", "compression": "^1.7.4", "cookie-parser": "^1.4.6", "cors": "^2.8.5", "dotenv": "^16.0.0", - "express": "^4.17.3", - "express-session": "^1.17.2", - "framer-motion": "6.2.9", - "immer": "^9.0.12", + "express": "^4.18.1", + "express-session": "^1.17.3", + "framer-motion": "6.3.3", + "immer": "^9.0.13", "js-cookie": "^3.0.1", "lodash": "^4.17.21", "multer": "^1.4.4", "pretty-error": "^4.0.0", "react": "^17.0.2", "react-dom": "^17.0.2", - "react-helmet-async": "^1.2.3", - "react-intl": "^5.24.8", - "react-redux": "^7.2.8", + "react-helmet-async": "1.2.3", + "react-intl": "5.24.8", + "react-redux": "^8.0.1", "react-router": "6.3.0", "react-router-dom": "6.3.0", - "redux": "^4.1.2", + "redux": "^4.2.0", "redux-saga": "^1.1.3", "redux-thunk": "^2.4.1", "spark-md5": "^3.0.1", - "webpack": "^5.72.0", + "webpack": "^5.72.1", "zustand": "^3.7.1" }, "devDependencies": { - "@babel/cli": "^7.17.6", - "@babel/core": "^7.17.9", - "@babel/plugin-proposal-class-properties": "^7.16.7", - "@babel/plugin-proposal-decorators": "^7.17.9", - "@babel/plugin-proposal-export-default-from": "^7.16.7", - "@babel/plugin-proposal-object-rest-spread": "^7.17.3", - "@babel/plugin-proposal-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-private-methods": "^7.16.11", + "@babel/cli": "^7.17.10", + "@babel/core": "^7.18.0", + "@babel/plugin-proposal-class-properties": "^7.17.12", + "@babel/plugin-proposal-decorators": "^7.17.12", + "@babel/plugin-proposal-export-default-from": "^7.17.12", + "@babel/plugin-proposal-object-rest-spread": "^7.18.0", + "@babel/plugin-proposal-optional-chaining": "^7.17.12", + "@babel/plugin-proposal-private-methods": "^7.17.12", "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-transform-modules-commonjs": "^7.17.9", - "@babel/plugin-transform-runtime": "^7.17.0", - "@babel/preset-env": "^7.16.11", - "@babel/preset-react": "^7.16.7", - "@babel/preset-typescript": "^7.16.7", + "@babel/plugin-transform-modules-commonjs": "^7.18.0", + "@babel/plugin-transform-runtime": "^7.18.0", + "@babel/preset-env": "^7.18.0", + "@babel/preset-react": "^7.17.12", + "@babel/preset-typescript": "^7.17.12", "@loadable/babel-plugin": "^5.13.2", "@loadable/webpack-plugin": "^5.15.2", - "@pmmmwh/react-refresh-webpack-plugin": "^0.5.5", + "@pmmmwh/react-refresh-webpack-plugin": "^0.5.6", "@types/compression": "^1.7.2", "@types/cookie-parser": "^1.4.2", "@types/cors": "^2.8.12", @@ -83,50 +83,49 @@ "@types/node": "^17.0.23", "@types/react": "^17.0.42", "@types/react-dom": "^17.0.14", - "@types/react-redux": "^7.1.23", "@types/webpack": "^5.28.0", - "@types/webpack-env": "^1.16.3", + "@types/webpack-env": "^1.17.0", "@types/webpack-hot-middleware": "^2.25.6", - "@typescript-eslint/eslint-plugin": "^5.18.0", - "@typescript-eslint/parser": "^5.18.0", - "autoprefixer": "^10.4.4", + "@typescript-eslint/eslint-plugin": "^5.25.0", + "@typescript-eslint/parser": "^5.25.0", + "autoprefixer": "^10.4.7", "babel-jest": "^27.5.1", - "babel-loader": "^8.2.4", - "babel-plugin-import": "^1.13.3", + "babel-loader": "^8.2.5", + "babel-plugin-import": "^1.13.5", "clean-webpack-plugin": "^4.0.0", - "core-js": "^3.21.1", + "core-js": "^3.22.5", "cross-env": "^7.0.3", "css-loader": "^6.7.1", "css-minimizer-webpack-plugin": "^3.4.1", - "eslint": "^8.11.0", + "eslint": "^8.15.0", "eslint-config-prettier": "^8.5.0", "eslint-import-resolver-typescript": "^2.7.1", "eslint-plugin-import": "^2.26.0", "eslint-plugin-jsx-a11y": "^6.5.1", "eslint-plugin-prettier": "^4.0.0", - "eslint-plugin-react": "^7.29.4", - "eslint-plugin-react-hooks": "^4.4.0", + "eslint-plugin-react": "^7.30.0", + "eslint-plugin-react-hooks": "^4.5.0", "eslint-webpack-plugin": "^3.1.1", "file-loader": "^6.2.0", - "fork-ts-checker-webpack-plugin": "^7.2.3", + "fork-ts-checker-webpack-plugin": "^7.2.11", "identity-obj-proxy": "^3.0.0", "jest": "^27.5.1", "mini-css-extract-plugin": "^2.6.0", "node-sass": "^7.0.1", "nodemon": "^2.0.15", - "postcss": "^8.4.12", + "postcss": "^8.4.14", "postcss-loader": "^6.2.1", "prettier": "^2.6.2", - "react-refresh": "^0.12.0", - "sass": "^1.50.0", + "react-refresh": "^0.13.0", + "sass": "^1.52.0", "sass-loader": "^12.6.0", "style-loader": "^3.3.1", "thread-loader": "^3.0.4", "typescript": "^4.5.5", "webpack-bundle-analyzer": "^4.5.0", "webpack-cli": "^4.9.2", - "webpack-dev-middleware": "^5.3.1", - "webpack-dev-server": "^4.8.1", + "webpack-dev-middleware": "^5.3.3", + "webpack-dev-server": "^4.9.0", "webpack-hot-middleware": "^2.25.1", "webpack-manifest-plugin": "^5.0.0", "webpack-merge": "^5.8.0", diff --git a/src/client/entry.tsx b/src/client/entry.tsx index 926b246..5460668 100644 --- a/src/client/entry.tsx +++ b/src/client/entry.tsx @@ -12,26 +12,18 @@ const place = document.querySelector("#__content__"); const preLoadEnvElement = document.querySelector("script#__preload_env__"); -const preLoadPropsElement = document.querySelector("script#__preload_props__"); - const preLoadStateElement = document.querySelector("script#__preload_state__"); const store = createUniversalStore({ initialState: JSON.parse(preLoadStateElement?.innerHTML || "{}") as StoreState }); window.__ENV__ = JSON.parse(preLoadEnvElement?.innerHTML || "{}"); -window.__INITIAL_PROPS_SSR__ = JSON.parse(preLoadPropsElement?.innerHTML || "{}"); - window.__PRELOAD_STORE_STATE__ = JSON.parse(preLoadStateElement?.innerHTML || "{}"); safeData(window.__ENV__); safeData(window as unknown as Record, "__ENV__"); -safeData(window.__INITIAL_PROPS_SSR__); - -safeData(window as unknown as Record, "__INITIAL_PROPS_SSR__"); - safeData(window.__PRELOAD_STORE_STATE__); safeData(window as unknown as Record, "__PRELOAD_STORE_STATE__"); diff --git a/src/components/LoadingBar/LoadingBar.tsx b/src/components/LoadingBar/LoadingBar.tsx index 6347c2b..89c1b5f 100644 --- a/src/components/LoadingBar/LoadingBar.tsx +++ b/src/components/LoadingBar/LoadingBar.tsx @@ -6,19 +6,18 @@ import { useMounted } from "hooks/useMounted"; import style from "./index.module.scss"; - let div: HTMLDivElement | undefined; -export const Bar = memo( - forwardRef(function Bar(_, ref) { - useEffectOnce(() => { - div = document.createElement("div"); - div.id = "__loading_bar__"; - document.body.prepend(div); - }); +const _Bar = forwardRef(function Bar(_, ref) { + useEffectOnce(() => { + div = document.createElement("div"); + div.id = "__loading_bar__"; + document.body.prepend(div); + }); + + const mounted = useMounted(); - const mounted = useMounted(); + return mounted ? createPortal(
, div as Element) : null; +}); - return mounted ? createPortal(
, div as Element) : null; - }) -); +export const Bar = memo(_Bar); diff --git a/src/components/RenderMatch.tsx b/src/components/RenderMatch.tsx index 8cb24ee..0caa1ce 100644 --- a/src/components/RenderMatch.tsx +++ b/src/components/RenderMatch.tsx @@ -8,12 +8,12 @@ import { getIsAnimateRouter } from "utils/env"; import { useLoadedLocation } from "./WrapperRoute"; export const RenderMatch = () => { - const location = useLoadedLocation(); - const all = useRoutes(allRoutes, location); + const loaded = useLoadedLocation(); + const all = useRoutes(allRoutes, loaded?.location); return getIsAnimateRouter() ? ( - + | Record>({}); +export const LoadedLocationContext = createContext["loaded"] | null>(null); export const WrapperRoute: WrapperRouteType = ({ children, routes, LoadingBar }) => { - const { location } = usePreLoad({ routes, preLoad, hydrate: hydrateLoad }); + const { loaded } = usePreLoad({ routes, preLoad }); // for pure client render - if (!location) return null; + if (!loaded) return null; return ( - + {children} diff --git a/src/config/action.ts b/src/config/action.ts index 112dcf9..5896f3d 100644 --- a/src/config/action.ts +++ b/src/config/action.ts @@ -1,8 +1,8 @@ enum actionName { + globalInitialProps = "globalInitialProps", currentToken = "currentToken", currentLang = "currentLang", currentLoading = "currentLoading", - currentInitialState = "currentInitialState", } export { actionName }; diff --git a/src/hooks/useGetInitialProps.ts b/src/hooks/useGetInitialProps.ts new file mode 100644 index 0000000..a25e2c4 --- /dev/null +++ b/src/hooks/useGetInitialProps.ts @@ -0,0 +1,17 @@ +import { useSelector } from "react-redux"; + +import { useLoadedLocation } from "components/WrapperRoute"; +import { generateInitialPropsKey } from "utils/preLoad"; + +import type { StoreState } from "types/store"; + +const globalInitialSelector = (state: StoreState) => state.client.globalInitialProps.data; + +export const useGetInitialProps = () => { + const globalInitialProps = useSelector(globalInitialSelector); + const loaded = useLoadedLocation(); + const propsKey = generateInitialPropsKey(loaded?.location.pathname || "", loaded?.query || new URLSearchParams()); + const props = globalInitialProps[propsKey]; + + return props; +}; diff --git a/src/hooks/useLang.ts b/src/hooks/useLang.ts index dbfd2f9..3247309 100644 --- a/src/hooks/useLang.ts +++ b/src/hooks/useLang.ts @@ -1,8 +1,9 @@ import cookie from "js-cookie"; import { useCallback, useRef } from "react"; -import { useDispatch, useSelector } from "react-redux"; +import { useSelector } from "react-redux"; import { apiName } from "config/api"; +import { useDispatch } from "store"; import { getDataAction_Server } from "store/reducer/server/share/action"; import { useChangeLoadingWithoutRedux } from "./useLoadingBar"; diff --git a/src/hooks/usePreLoad.ts b/src/hooks/usePreLoad.ts index 2cb19da..d31f290 100644 --- a/src/hooks/usePreLoad.ts +++ b/src/hooks/usePreLoad.ts @@ -1,20 +1,26 @@ import cookie from "js-cookie"; -import { useEffect, useMemo, useRef, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { useStore } from "react-redux"; -import { useLocation, useNavigate } from "react-router"; +import { useLocation, useNavigate, useParams } from "react-router"; +import { useSearchParams } from "react-router-dom"; import { log } from "utils/log"; +import { generateInitialPropsKey } from "utils/preLoad"; import { useChangeLoadingWithoutRedux } from "./useLoadingBar"; +import type { Params } from "react-router"; import type { UsePreLoadType } from "types/hooks"; +import type { StoreState } from "types/store"; /* WrapperRoute */ -const usePreLoad: UsePreLoadType = ({ routes, preLoad, hydrate }) => { +const usePreLoad: UsePreLoadType = ({ routes, preLoad }) => { const isRedirect = useRef(); - const store = useStore(); + const store = useStore(); const location = useLocation(); const navigate = useNavigate(); + const params = useParams(); + const [query] = useSearchParams(); const { start, end } = useChangeLoadingWithoutRedux(); // for pure client render, need preload data const firstLoad = useRef(__CSR__ ? false : true); @@ -24,29 +30,22 @@ const usePreLoad: UsePreLoadType = ({ routes, preLoad, hydrate }) => { const timer2 = useRef(null); const storeRef = useRef(store); // for pure client render, there are not exist loaded location - const [loadedLocation, setLoadedLocation] = useState(__CSR__ ? undefined : location); + const [loadedLocation, setLoadedLocation] = useState(__CSR__ ? undefined : { location, params, query }); - loadingPath.current = location.pathname; + loadingPath.current = generateInitialPropsKey(location.pathname, query); - loadedPath.current = loadedLocation?.pathname; + loadedPath.current = loadedLocation ? generateInitialPropsKey(loadedLocation.location.pathname, loadedLocation.query) : ""; storeRef.current = store; - useMemo(() => { - if (loadedLocation?.pathname) { - hydrate(routes, loadedLocation.pathname); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - useEffect(() => { // skip first load if need if (!firstLoad.current) { - const isRedirectCurrentPath = isRedirect.current && isRedirect.current === location.pathname; + const isRedirectCurrentPath = isRedirect.current && isRedirect.current === generateInitialPropsKey(location.pathname, query); if (!isRedirectCurrentPath) { end(); } - if (loadedPath.current !== location.pathname) { + if (loadedPath.current !== generateInitialPropsKey(location.pathname, query)) { if (!isRedirectCurrentPath) { timer1.current && clearTimeout(timer1.current) && (timer1.current = null); timer2.current && clearTimeout(timer2.current) && (timer2.current = null); @@ -56,11 +55,16 @@ const usePreLoad: UsePreLoadType = ({ routes, preLoad, hydrate }) => { } // 分离每次load逻辑 避免跳转错乱 - const currentLoad = (location: ReturnType): void => { - preLoad(routes, location.pathname, storeRef.current).then((config) => { - if (location.pathname === loadingPath.current) { - const { redirect, error, cookies } = config; - isRedirect.current = typeof redirect === "object" ? redirect.redirect : redirect; + const currentLoad = (location: ReturnType, params: Params, query: URLSearchParams): void => { + preLoad(routes, location.pathname, query, storeRef.current).then((config) => { + const currentLoadKey = generateInitialPropsKey(location.pathname, query); + if (currentLoadKey === loadingPath.current) { + const { redirect, error, cookies } = config || {}; + if (redirect) { + isRedirect.current = generateInitialPropsKey(redirect.location.pathName, redirect.location.query); + } else { + isRedirect.current = ""; + } if (cookies) { Object.keys(cookies).forEach((key) => cookie.set(key, cookies[key])); } @@ -68,13 +72,13 @@ const usePreLoad: UsePreLoadType = ({ routes, preLoad, hydrate }) => { log(`error ${error.toString()}`, "error"); end(); } else if (redirect) { - navigate(typeof redirect === "object" ? redirect.redirect : redirect); + navigate(isRedirect.current); } else { timer2.current = setTimeout(() => { timer1.current && clearTimeout(timer1.current) && (timer1.current = null); - if (loadingPath.current === location.pathname) { + if (loadingPath.current === currentLoadKey) { end(); - setLoadedLocation(location); + setLoadedLocation({ location, params, query }); } }, 50); } @@ -82,14 +86,14 @@ const usePreLoad: UsePreLoadType = ({ routes, preLoad, hydrate }) => { }); }; - currentLoad(location); + currentLoad(location, params, query); } } else { firstLoad.current = false; } - }, [location, preLoad, routes, navigate, end, start]); + }, [location, preLoad, routes, navigate, end, start, params, query]); - return { location: loadedLocation }; + return { loaded: loadedLocation }; }; export { usePreLoad }; diff --git a/src/pages/Foo/:id.tsx b/src/pages/Foo/:id.tsx index 7928d28..3a770ab 100644 --- a/src/pages/Foo/:id.tsx +++ b/src/pages/Foo/:id.tsx @@ -8,9 +8,9 @@ const Id: PreLoadComponentType = () => { return
params: {f.id}
; }; -export const getInitialState: GetInitialStateType = ({ match, config }) => { - console.log("当前id参数为:", match.params.id); - console.log("server side request", config?.req); +export const getInitialState: GetInitialStateType = ({ query, params }) => { + console.log("当前id参数为:", params.id); + console.log("当前query为", query); }; export default Id; diff --git a/src/pages/Great.tsx b/src/pages/Great.tsx index 48ca381..05c995a 100644 --- a/src/pages/Great.tsx +++ b/src/pages/Great.tsx @@ -1,3 +1,5 @@ +import { useSearchParams } from "react-router-dom"; + import { apiName } from "config/api"; import { getDataAction_Server } from "store/reducer/server/share/action"; @@ -5,7 +7,13 @@ import type { GetInitialStateType, PreLoadComponentType } from "types/components const Great: PreLoadComponentType<{ blog: string[] }> = (props) => { console.log(props, "test auto inject"); - return
Great rt, {props?.blog?.join(", ")}
; + const [, setSearch] = useSearchParams(); + return ( +
+ Great rt, {props?.blog?.join(", ")} 454545 + +
+ ); }; export const getInitialState: GetInitialStateType = async ({ store }) => { @@ -13,7 +21,7 @@ export const getInitialState: GetInitialStateType = async ({ store }) => { await store.dispatch(getDataAction_Server({ name: apiName.blog })); console.log(store.sagaTask?.isRunning(), store.sagaTask?.isCancelled()); console.log("dispatch done"); - return { props: { blog: [1, 2, 3, 4, 5, 6, 7, 7, 8, 9, 0], foo: { a: 1, b: 2, c: 3 } }, cookies: { foo: "foo", bar: "bar" } }; + return { props: { blog: [1, 2, 3, 4, 5, 6, 7, 7, 8, 9, 0, "1", "2", "3", "4", "5"], foo: { a: 1, b: 2, c: 3 } }, cookies: { foo: "foo", bar: "bar" } }; }; export default Great; diff --git a/src/router/routes.tsx b/src/router/routes.tsx index c355621..a59fdf2 100644 --- a/src/router/routes.tsx +++ b/src/router/routes.tsx @@ -2,6 +2,7 @@ import loadable from "@loadable/component"; import { Layout } from "components/Layout"; import { UI } from "components/UI"; +import { AutoInjectInitialProps } from "utils/preLoad"; import { dynamicRouteConfig } from "./dynamicRoutes"; import { filter } from "./tools"; @@ -35,7 +36,9 @@ const routes: PreLoadRouteConfig[] = [ const dynamicRoutes = dynamicRouteConfig .map((it) => ({ path: it.componentPath === "404" ? "/*" : it.path, - component: loadable(() => import(`../pages/${it.componentPath}`)), + component: loadable(() => import(`../pages/${it.componentPath}`), { + resolveComponent: (module) => AutoInjectInitialProps(module.default), + }), })) .map(({ path, component: Component }) => ({ path: path, Component, element: })); diff --git a/src/server/middleware/renderPage/compose.ts b/src/server/middleware/renderPage/compose.ts index d2592b9..4f1ffbd 100644 --- a/src/server/middleware/renderPage/compose.ts +++ b/src/server/middleware/renderPage/compose.ts @@ -3,7 +3,7 @@ import type { Request, Response } from "express"; import type { SagaStore } from "types/store"; -type BaseArgs = { req: Request; res: Response; store?: SagaStore; env?: { [p: string]: unknown }; lang?: string; serverSideProps?: { [key: string]: any } }; +type BaseArgs = { req: Request; res: Response; store?: SagaStore; env?: { [p: string]: unknown }; lang?: string }; export type OverrideBase = BaseArgs & T; diff --git a/src/server/middleware/renderPage/middleware/loadStore.ts b/src/server/middleware/renderPage/middleware/loadStore.ts index f03dcc8..c5983a2 100644 --- a/src/server/middleware/renderPage/middleware/loadStore.ts +++ b/src/server/middleware/renderPage/middleware/loadStore.ts @@ -11,7 +11,7 @@ export const loadStore: Middleware = (next) => async (args) => { throw new ServerError(`server 初始化失败 lang: ${lang}, store: ${store}`, 500); } - const { error, redirect, serverSideProps, cookies } = await preLoad(allRoutes, req.url, store, { req, lang }); + const { error, redirect, cookies } = (await preLoad(allRoutes, req.path, new URLSearchParams(req.url.split("?")[1]), store)) || {}; if (cookies) { Object.keys(cookies).forEach((key) => { @@ -24,14 +24,11 @@ export const loadStore: Middleware = (next) => async (args) => { } if (redirect) { - if (typeof redirect === "object") { - res.writeHead(redirect.code, { location: redirect.redirect }); - } else { - res.writeHead(302, { Location: redirect }); - } + const query = redirect.location.query.toString(); + const path = query.length ? redirect.location.pathName + "?" + query : redirect.location.pathName; + res.writeHead(redirect.code || 302, { location: path }); res.end(); } else { - args.serverSideProps = serverSideProps; await next(args); } }; diff --git a/src/server/middleware/renderPage/renderCSR.tsx b/src/server/middleware/renderPage/renderCSR.tsx index 1866644..709477f 100644 --- a/src/server/middleware/renderPage/renderCSR.tsx +++ b/src/server/middleware/renderPage/renderCSR.tsx @@ -11,7 +11,7 @@ import { globalEnv, initLang, initStore, loadCookie, loadLang, loadStore } from import type { AnyAction } from "./compose"; // 客户端渲染 -const targetRender: AnyAction = async ({ res, store, lang, env, serverSideProps = {} }) => { +const targetRender: AnyAction = async ({ res, store, lang, env }) => { if (!store || !lang || !env) { throw new ServerError("server 初始化失败", 500); } @@ -28,7 +28,6 @@ const targetRender: AnyAction = async ({ res, store, lang, env, serverSideProps lang={JSON.stringify(lang)} script={scriptElements} link={linkElements.concat(styleElements)} - serverSideProps={JSON.stringify(serverSideProps)} reduxInitialState={JSON.stringify(store.getState())} /> ) diff --git a/src/server/middleware/renderPage/renderSSR/index.ts b/src/server/middleware/renderPage/renderSSR/index.ts index d706aec..e1937ec 100644 --- a/src/server/middleware/renderPage/renderSSR/index.ts +++ b/src/server/middleware/renderPage/renderSSR/index.ts @@ -6,21 +6,21 @@ import { globalEnv, initLang, initStore, loadCookie, loadLang, loadStore } from import type { AnyAction } from "../compose"; -const targetRender: AnyAction = async ({ req, res, store, lang, env, serverSideProps = {} }) => { +const targetRender: AnyAction = async ({ req, res, store, lang, env }) => { if (!store || !lang || !env) { throw new ServerError("初始化失败", 500); } else { if (__UI__ === "antd") { const { targetRender } = require("./renderAntDesign"); - return targetRender({ req, res, store, lang, env, serverSideProps }); + return targetRender({ req, res, store, lang, env }); } if (__UI__ === "material") { const { targetRender } = require("./renderMaterial"); - return targetRender({ req, res, store, lang, env, serverSideProps }); + return targetRender({ req, res, store, lang, env }); } if (__UI__ === "chakra") { const { targetRender } = require("./renderChakra"); - return targetRender({ req, res, store, lang, env, serverSideProps }); + return targetRender({ req, res, store, lang, env }); } } }; diff --git a/src/server/middleware/renderPage/renderSSR/renderAntDesign.tsx b/src/server/middleware/renderPage/renderSSR/renderAntDesign.tsx index 8f4a7c5..320b6f7 100644 --- a/src/server/middleware/renderPage/renderSSR/renderAntDesign.tsx +++ b/src/server/middleware/renderPage/renderSSR/renderAntDesign.tsx @@ -10,7 +10,7 @@ import { manifestLoadable } from "utils/manifest"; import type { SafeAction } from "../compose"; -export const targetRender: SafeAction = async ({ req, res, store, lang, env, serverSideProps }) => { +export const targetRender: SafeAction = async ({ req, res, store, lang, env }) => { const helmetContext = {}; const content = ( @@ -43,7 +43,6 @@ export const targetRender: SafeAction = async ({ req, res, store, lang, env, ser script={scriptElements} helmetContext={helmetContext} link={linkElements.concat(styleElements)} - serverSideProps={JSON.stringify(serverSideProps)} reduxInitialState={JSON.stringify(store.getState())} > {body} diff --git a/src/server/middleware/renderPage/renderSSR/renderChakra.tsx b/src/server/middleware/renderPage/renderSSR/renderChakra.tsx index 43f0ddd..36f19b1 100644 --- a/src/server/middleware/renderPage/renderSSR/renderChakra.tsx +++ b/src/server/middleware/renderPage/renderSSR/renderChakra.tsx @@ -15,7 +15,7 @@ import { manifestLoadable } from "utils/manifest"; import type { SafeAction } from "../compose"; -export const targetRender: SafeAction = async ({ req, res, store, lang, env, serverSideProps }) => { +export const targetRender: SafeAction = async ({ req, res, store, lang, env }) => { const helmetContext = {}; const cache = createEmotionCache(); const { extractCriticalToChunks } = createEmotionServer(cache); @@ -60,7 +60,6 @@ export const targetRender: SafeAction = async ({ req, res, store, lang, env, ser helmetContext={helmetContext} emotionChunks={emotionChunks} link={linkElements.concat(styleElements)} - serverSideProps={JSON.stringify(serverSideProps)} reduxInitialState={JSON.stringify(store.getState())} > {body} diff --git a/src/server/middleware/renderPage/renderSSR/renderMaterial.tsx b/src/server/middleware/renderPage/renderSSR/renderMaterial.tsx index 7e1f9dd..97070e1 100644 --- a/src/server/middleware/renderPage/renderSSR/renderMaterial.tsx +++ b/src/server/middleware/renderPage/renderSSR/renderMaterial.tsx @@ -16,7 +16,7 @@ import { manifestLoadable } from "utils/manifest"; import type { SafeAction } from "../compose"; -export const targetRender: SafeAction = async ({ req, res, store, lang, env, serverSideProps }) => { +export const targetRender: SafeAction = async ({ req, res, store, lang, env }) => { const helmetContext = {}; const cache = createEmotionCache(); const { extractCriticalToChunks } = createEmotionServer(cache); @@ -60,7 +60,6 @@ export const targetRender: SafeAction = async ({ req, res, store, lang, env, ser helmetContext={helmetContext} emotionChunks={emotionChunks} link={linkElements.concat(styleElements)} - serverSideProps={JSON.stringify(serverSideProps)} reduxInitialState={JSON.stringify(store.getState())} > {body} diff --git a/src/store/index.ts b/src/store/index.ts index b514dbe..1687d8c 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -1,4 +1,5 @@ -import { createStore, applyMiddleware, compose } from "redux"; +import { useDispatch as OriginalUseDispatch } from "react-redux"; +import { legacy_createStore as createStore, applyMiddleware, compose } from "redux"; import createSagaMiddleware from "redux-saga"; import thunkMiddleware from "redux-thunk"; @@ -6,7 +7,8 @@ import { rootReducer } from "./reducer"; import { rootSaga } from "./saga"; import { SagaManager } from "./saga/utils"; -import type { Middleware } from "redux"; +import type { Middleware, AnyAction } from "redux"; +import type { ThunkDispatch } from "redux-thunk"; import type { SagaStore, StoreState } from "types/store"; type CreateStoreProps = { @@ -44,3 +46,9 @@ export const createUniversalStore = (props: CreateStoreProps = {}): SagaStore => return store; }; + +export const useDispatch = () => { + const dispatch = OriginalUseDispatch, AnyAction>>(); + + return dispatch; +}; diff --git a/src/store/reducer/client/action/currentInitialState.ts b/src/store/reducer/client/action/globalInitialProps.ts similarity index 60% rename from src/store/reducer/client/action/currentInitialState.ts rename to src/store/reducer/client/action/globalInitialProps.ts index 3c36500..e90516d 100644 --- a/src/store/reducer/client/action/currentInitialState.ts +++ b/src/store/reducer/client/action/globalInitialProps.ts @@ -7,12 +7,11 @@ import { clientAction } from "../share/action"; import type { Reducer } from "redux"; import type { ReducerState, ReducerStateAction, ReducerStateActionMapType } from "types/store/reducer"; -// support cache getInitialState function props? type CurrentState = ReducerState>; -const initialState: CurrentState = { data: {}, error: null, loading: false, loaded: false }; +const initState: CurrentState = { data: {}, error: null, loading: false, loaded: false }; -const initialStateReducer: Reducer = (state: CurrentState = initialState, action: ReducerStateAction>) => { +const initialPropsReducer: Reducer = (state: CurrentState = initState, action: ReducerStateAction>) => { const actionReducer = actionReducerMap[action.type]; if (actionReducer) { return actionReducer(state, action); @@ -22,20 +21,20 @@ const initialStateReducer: Reducer = (state: CurrentState = initia }; const actionReducerMap: ReducerStateActionMapType> = { - [clientAction.SET_DATA_LOADING(actionName.currentInitialState)]: (state, action) => + [clientAction.SET_DATA_LOADING(actionName.globalInitialProps)]: (state, action) => produce(state, (proxy) => { proxy.error = null; - proxy.loading = action.loadingState ?? true; + proxy.loading = action.loadingState || true; proxy.loaded = false; }), - [clientAction.SET_DATA_SUCCESS(actionName.currentInitialState)]: (state, action) => + [clientAction.SET_DATA_SUCCESS(actionName.globalInitialProps)]: (state, action) => produce(state, (proxy) => { proxy.data = { ...proxy.data, ...action.data }; proxy.error = null; proxy.loading = false; proxy.loaded = true; }), - [clientAction.SET_DATA_FAIL(actionName.currentInitialState)]: (state, action) => + [clientAction.SET_DATA_FAIL(actionName.globalInitialProps)]: (state, action) => produce(state, (proxy) => { proxy.error = action.error; proxy.loading = false; @@ -43,4 +42,4 @@ const actionReducerMap: ReducerStateActionMapType> = { }), }; -export { initialStateReducer }; +export { initialPropsReducer }; diff --git a/src/store/reducer/client/action/index.ts b/src/store/reducer/client/action/index.ts index 64d7b10..1dfc7ce 100644 --- a/src/store/reducer/client/action/index.ts +++ b/src/store/reducer/client/action/index.ts @@ -1,4 +1,4 @@ export { tokenReducer } from "./currentToken"; export { langReducer } from "./currentLang"; -export { initialStateReducer } from "./currentInitialState"; export { loadingReducer } from "./currentLoading"; +export { initialPropsReducer } from "./globalInitialProps"; diff --git a/src/store/reducer/client/index.ts b/src/store/reducer/client/index.ts index b23631e..23937fb 100644 --- a/src/store/reducer/client/index.ts +++ b/src/store/reducer/client/index.ts @@ -2,11 +2,11 @@ import { combineReducers } from "redux"; import { actionName } from "config/action"; -import { langReducer, tokenReducer, loadingReducer, initialStateReducer } from "./action"; +import { langReducer, tokenReducer, loadingReducer, initialPropsReducer } from "./action"; export const client = combineReducers({ [actionName.currentToken]: tokenReducer, [actionName.currentLang]: langReducer, [actionName.currentLoading]: loadingReducer, - [actionName.currentInitialState]: initialStateReducer, + [actionName.globalInitialProps]: initialPropsReducer, }); diff --git a/src/template/Html.tsx b/src/template/Html.tsx index 5f7c55a..0a4f0fc 100644 --- a/src/template/Html.tsx +++ b/src/template/Html.tsx @@ -10,7 +10,6 @@ type HTMLProps = { children?: string; link?: React.ReactElement[]; script?: React.ReactElement[]; - serverSideProps?: string; reduxInitialState?: string; emotionChunks?: EmotionCriticalToChunks; helmetContext?: { helmet?: HelmetServerState }; @@ -18,17 +17,7 @@ type HTMLProps = { // NOTE this template only run on the server // like _document.js in the next.js -export const HTML = ({ - lang, - children, - link = [], - script = [], - serverSideProps = "{}", - reduxInitialState = "{}", - helmetContext = {}, - emotionChunks, - env = "{}", -}: HTMLProps) => { +export const HTML = ({ lang, children, link = [], script = [], reduxInitialState = "{}", helmetContext = {}, emotionChunks, env = "{}" }: HTMLProps) => { const { helmet } = helmetContext; return ( @@ -57,7 +46,6 @@ export const HTML = ({ }} />