reactjs NextJS、@react-keycloak/ssr '和url参数的无限循环问题?

2cmtqfgy  于 2023-02-12  发布在  React
关注(0)|答案(1)|浏览(143)

当我从@react-keycloak/ssr npm包添加SSRKeycloakProvider组件时,我在NextJS项目中遇到了浏览器无限循环问题。此无限循环仅发生在特定应用程序的“报告”页面上。
我的调查使我相信这与keycloak集成处理cookie的方式有关,在报告页面中,我也使用了windows.replaceState()javascript函数。
每次循环开始时,我从应用程序得到的消息如下:

[Function: setReportq]
Warning: useLayoutEffect does nothing on the server, because its effect cannot be encoded into the server renderer's output format. This will lead to a mismatch between the initial, non-hydrated UI and the intended UI. To avoid this, useLayoutEffect should only be used in components that render exclusively on the client. See https://reactjs.org/link/uselayouteffect-ssr for common fixes.
at Overflow (/home/ubuntu/growth-admin/node_modules/rc-overflow/lib/Overflow.js:42:32)
at SelectSelector (/home/ubuntu/growth-admin/node_modules/rc-select/lib/Selector/MultipleSelector.js:36:18)
at div
at Selector (/home/ubuntu/growth-admin/node_modules/rc-select/lib/Selector/index.js:38:35)
at Trigger (/home/ubuntu/growth-admin/node_modules/rc-trigger/lib/index.js:79:36)
at SelectTrigger (/home/ubuntu/growth-admin/node_modules/rc-select/lib/SelectTrigger.js:74:25)
at div
at BaseSelect (/home/ubuntu/growth-admin/node_modules/rc-select/lib/BaseSelect.js:67:18)
at Select (/home/ubuntu/growth-admin/node_modules/rc-select/lib/Select.js:66:18)
at InternalSelect (/home/ubuntu/growth-admin/node_modules/antd/lib/select/index.js:55:31)
at div
at div
at div
at Col (/home/ubuntu/growth-admin/node_modules/antd/lib/grid/col.js:59:33)
at FormItemInput (/home/ubuntu/growth-admin/node_modules/antd/lib/form/FormItemInput.js:44:25)
at div
at Row (/home/ubuntu/growth-admin/node_modules/antd/lib/grid/row.js:56:34)
at FormItem (/home/ubuntu/growth-admin/node_modules/antd/lib/form/FormItem.js:101:20)
at form
at Form (/home/ubuntu/growth-admin/node_modules/rc-field-form/lib/Form.js:33:19)
at SizeContextProvider (/home/ubuntu/growth-admin/node_modules/antd/lib/config-provider/SizeContext.js:19:23)
at InternalForm (/home/ubuntu/growth-admin/node_modules/antd/lib/form/Form.js:66:27)
at div
at Report (webpack-internal:///./common/components/DominoReport/index.js:152:3)
at div
at appClassicstyle__ContentWrapper (/home/ubuntu/growth-admin/node_modules/styled-components/dist/styled-components.cjs.js:1:19220)
at div
at appClassicstyle__AppWrapper (/home/ubuntu/growth-admin/node_modules/styled-components/dist/styled-components.cjs.js:1:19220)
at AppClassic (webpack-internal:///./common/components/Admin/report.js:27:3)
at div
at main
at Basic (/home/ubuntu/growth-admin/node_modules/antd/lib/layout/layout.js:78:25)
at Content (/home/ubuntu/growth-admin/node_modules/antd/lib/layout/layout.js:61:37)
at section
at BasicLayout (/home/ubuntu/growth-admin/node_modules/antd/lib/layout/layout.js:93:34)
at Layout (/home/ubuntu/growth-admin/node_modules/antd/lib/layout/layout.js:61:37)
at section
at BasicLayout (/home/ubuntu/growth-admin/node_modules/antd/lib/layout/layout.js:93:34)
at Layout (/home/ubuntu/growth-admin/node_modules/antd/lib/layout/layout.js:61:37)
at exports.ThemeProvider (/home/ubuntu/growth-admin/node_modules/styled-components/dist/styled-components.cjs.js:1:24917)
at Growth (webpack-internal:///./containers/Admin/growth.js:81:3)
at AppClassic (webpack-internal:///./pages/report.js:19:3)
at ThemeProvider (/home/ubuntu/growth-admin/node_modules/@material-ui/styles/ThemeProvider/ThemeProvider.js:48:24)
at KeycloakProvider (/home/ubuntu/growth-admin/node_modules/@react-keycloak/core/lib-commonjs/provider.js:72:51)
at SSRKeycloakProvider (/home/ubuntu/growth-admin/node_modules/@react-keycloak/ssr/lib-commonjs/SSRKeycloakProvider.js:64:28)
at CustomApp (webpack-internal:///./pages/_app.tsx:63:3)
at StylesProvider (/home/ubuntu/growth-admin/node_modules/@material-ui/styles/StylesProvider/StylesProvider.js:57:24)
at ae (/home/ubuntu/growth-admin/node_modules/styled-components/dist/styled-components.cjs.js:1:13296)
at AppContainer (/home/ubuntu/growth-admin/node_modules/next/dist/server/render.js:293:29)

上面的消息提到了parseCookies函数(in _app.tsx:63:3),pages/index.tsx第20行基本上是这一行:

const parsedToken: ParsedToken | undefined = keycloak?.tokenParsed

、在Growth组件中设置URL参数的windows.replaceState()函数,以及同样位于Growth组件中的特定reportq()函数。
下面是my _app.tsx,我相信parseCookies函数在这里很有用:

import React, { useEffect } from "react"
import App from 'next/app'
import { SSRKeycloakProvider, SSRCookies } from '@react-keycloak/ssr'
import cookie from 'cookie'
import type { IncomingMessage } from 'http'
import { ThemeProvider } from '@material-ui/core/styles';
import theme from '../theme';

const KC_URL = process.env.NEXT_PUBLIC_KC_URL;
const KC_REALM = process.env.NEXT_PUBLIC_KC_REALM
const KC_CLIENT_ID = process.env.NEXT_PUBLIC_KC_CLIENT_ID

const keycloakCfg = {
  realm: KC_REALM,
  url: KC_URL,
  clientId: KC_CLIENT_ID
}
interface InitialProps {
  cookies: unknown
}

export default function CustomApp({ Component, pageProps, cookies }) {
  
const initOptions = {
    onLoad: 'login-required',
    checkLoginIframe: false
  }

  return (
    <SSRKeycloakProvider
      keycloakConfig={keycloakCfg}
      persistor={SSRCookies(cookies)}
      initOptions={initOptions}
    >
      <ThemeProvider theme={theme}>
          <Component {...pageProps} />
      </ThemeProvider>
    </SSRKeycloakProvider>
  );
}

// I think the cookies and this function have to do with the issue
function parseCookies(req?: IncomingMessage) {
  if (!req || !req.headers) {
    return {}
}
  return cookie.parse(req.headers.cookie || '')
}

CustomApp.getInitialProps = async (appContext) => {
  // Your static props paths
  const staticPropsPaths = [
    "/paper/[paperId]/[paperName]",
    "/hubs"
  ]

  if (process.browser || !staticPropsPaths.includes(appContext.router.route)) {
    const appProps = await App.getInitialProps(appContext)
    return { ...appProps, cookies: parseCookies(appContext?.ctx?.req) }
  }
}

这是我的索引.tsx:

import type { NextPage } from 'next'
import { useKeycloak } from '@react-keycloak/ssr'
import type { KeycloakInstance, KeycloakTokenParsed } from 'keycloak-js'
import Growth from '../containers/Admin/growth'

type ParsedToken = KeycloakTokenParsed & {
  email?: string
  preferred_username?: string
  given_name?: string
  family_name?: string
}

const Home = ({ query }) => {
   const { keycloak } = useKeycloak<KeycloakInstance>()
   const parsedToken: ParsedToken | undefined = keycloak?.tokenParsed

   const loggedinState = keycloak?.authenticated ? (
     <span className="text-success">logged in</span>
   ) : (
     <span className="text-danger">NOT logged in</span>
   )

  const welcomeMessage =
    keycloak?.authenticated || (keycloak && parsedToken)
      ? `Welcome back ${parsedToken?.preferred_username ?? ''}!`
      : 'Welcome ! Please login to continue.'

  return <Growth query={query} page={'home'} />
}

Home.getInitialProps = async ({ query, res }) => {
  return { query }
}

export default Home

增长代码如下:我认为增长部分的利益线:

window.history.replaceState('state', 'Growth ', `${BASE_URL}${page}${reportq}`)

增长部分:

const Growth = ({ query, page }) => {
    const { keycloak, initialized } = useKeycloak()
    const router = useRouter()
    let [p, setP] = useState(page)

    let reportq;
    let prospectq;
    
    // I believe this function is involved
    const setReportq = (params) => {
        window.sessionStorage.setItem("reportq", params)
    }

    const setProspectq = (params) => {
        window.sessionStorage.setItem("prospectq", params)
    }

    useEffect(() => {
        if (typeof window !== 'undefined') {
            reportq = window.sessionStorage.getItem('reportq'); 
        if (!reportq)
            reportq = '';
        prospectq = window.sessionStorage.getItem('prospectq');
        if (!prospectq)
            prospectq = '';
    }
    if (typeof window !== 'undefined' && page == 'report') {
        const keys = Object.keys(query);

        let params = "?";
        for (let i = 0; i < keys.length; i++) {
            params += `${keys[i]}=${encodeURIComponent(query[keys[i]])}&`
        }
        // console.log("eval reportq vs query", { reportq, params })
        if (!reportq && keys && keys.length > 0) {
            console.log("growth line 78 setting reportq")
            setReportq(params)
        }
        else {
            if (params != reportq) {
               console.log("growth line 81 updating url with ", reportq)
               window.history.replaceState('state', 'Growth ', `${BASE_URL}${page}${reportq}`)
            }
        }
    }
        })

    const key = query.key;

    const setPage = (page) => {
        setP(page)
        setTimeout(() => {
            const newUrl = `${BASE_URL}${page == 'home' ? '' : page}${page == 'report' ? reportq : page == 'prospect' ? prospectq ? prospectq : `?key=${key}` : `?key=${key}`}`
        router.push(newUrl);
        }, 1);
    }

return (
    <ThemeProvider theme={theme}>
        <>
            <Head>
                <title>Growth</title>
                <meta name="robots" content="noindex" />
                <meta name="theme-color" content="#2563FF" />
            </Head>
       
            <Layout>
                <Sider
                    style={{
                        overflow: 'auto',
                        height: '100vh',
                        position: 'fixed',
                        left: 0,
                    }}
                >
                    
                    <Menu theme="dark" mode="inline" defaultSelectedKeys={[page]}>
                        <Menu.Item key="report" onClick={() => setPage('report')}>
                            Reports
                        </Menu.Item>
                    </Menu>
                </Sider>
                <Layout className="site-layout" style={{ marginLeft: 200 }}>
                            {p == 'report' && <Report query={query} setReportq={setReportq} />}
                
                </Layout>
            </Layout>
        </>
    </ThemeProvider >);
}
Growth.getInitialProps = async ({ query, res }) => {
    return { query }
}
export default Growth;
8xiog9wr

8xiog9wr1#

负载变化:“需要登录”才能加载:“勾选”,

相关问题