作为初始状态值的功能组件在React.memo中抛出未定义的子级而不进行包装



尝试将DefaultLayout组件设置为初始状态值。它抛出无法取消未定义的属性子级的结构。

如果我在React.memo中包装DefaultLayout组件,它可以正常工作,没有任何错误,即导出默认的React.moom(DefaultLayout(

谁能解释一下这种行为的原因吗。

请找到沙盒链接

https://codesandbox.io/s/autumn-firefly-qp5gh?file=/pages/index.js

布局.js

import React, { useEffect, useState } from 'react'
import { AppLayout } from 'utilities/appComponentConfig'
import { useGlobalUI } from 'store/GlobalUI'
import { APP_TYPE } from 'utilities/Constants'
import { fetchKioskInfo } from '../services/kiosk'
const Layout = ({ Pages, pageProps, cookie }) => {
const { setAppType, setAgentCookie } = useGlobalUI()
const [Component, setComponent] = useState(AppLayout[APP_TYPE.WEB])
setAgentCookie(cookie)
useEffect(() => {
const fetchKiosk = async () => {
const kioskDetails = await fetchKioskInfo(cookie)
if (kioskDetails?.length > 0) {
setAppType(APP_TYPE.KIOSK)
return setComponent(AppLayout[APP_TYPE.KIOSK])
} else {
setAppType(APP_TYPE.WEB)
return setComponent(AppLayout[APP_TYPE.WEB])
}
}
if(cookie?.includes('KIOSK'))fetchKiosk()
}, [])
return (
<>
{Component ? (
<Component pageProps={pageProps}>
<Pages {...pageProps} />
</Component>
) : null}
</>
)
}
export default Layout

appComponentConfig.js

import { APP_TYPE } from './Constants'
import DefaultLayout from 'layouts/DefaultLayout'
import KioskLayout from 'layouts/KioskLayout'
const AppLayout = {
[APP_TYPE.WEB]: DefaultLayout,
[APP_TYPE.KIOSK]: KioskLayout,
}
export { AppLayout }

DefaultLayout.js

const DefaultLayout = ({ children, pageProps }) => {
const mainNode = pageProps.main || {}
const settings = mainNode.settings || {}
const showFooter = !settings.hideFooter
const errorDetail = _find(pageProps, (item) => item.error && item.status)
const router = useRouter()
return (
<>
<div style={{ display: 'none' }} className="version">
Version 1.0.5
</div>
</div>
</>
)
}
export default DefaultLayout

_app.js

import React, { useEffect } from 'react'
import { useCookie } from 'next-cookie'
import '../styles/main.css'
import UserProvider from '../store/User'
import PageProvider from '../store/Page'
import GlobalUIProvider from '../store/GlobalUI'
import BookingProvider from '../store/Booking'
import ExtraProvider from '../store/Extras'
import CartProvider from '../store/Cart'
import CheckoutProvider from '../store/Checkout'
import { useRouter } from 'next/router'
import { storePathValues } from '../utilities/helperFunctions'
import Layout from 'layouts/Layout'
const App = ({ Component: Pages, pageProps, cookie }) => {
const router = useRouter()
return (
<>
<PageProvider model={pageProps}>
<GlobalUIProvider>
<UserProvider>
<CartProvider>
<CheckoutProvider>
<BookingProvider>
<ExtraProvider>
<Layout
Pages={Pages}
pageProps={pageProps}
cookie={agentCookie}
/>
</ExtraProvider>
</BookingProvider>
</CheckoutProvider>
</CartProvider>
</UserProvider>
</GlobalUIProvider>
</PageProvider>
</>
)
}
export default App

可能是因为React.memo是一个高阶组件,即它以React组件为参数,返回一个装饰的React组件。也许这与处理导出的顺序有关,并且使用memoHOC可以对此进行调整。

不管怎样,我认为将React组件存储在状态中有点反模式。我建议将当前的";活动的";CCD_ 3值,并导出该CCD_。

const Layout = ({ Pages, pageProps, cookie }) => {
const { setAppType, setAgentCookie } = useGlobalUI();
const [componentType, setComponentType] = useState(APP_TYPE.WEB);
setAgentCookie(cookie);
useEffect(() => {
const fetchKiosk = async () => {
const kioskDetails = await fetchKioskInfo(cookie);
const type = kioskDetails?.length ? APP_TYPE.KIOSK : APP_TYPE.WEB;
setAppType(type);
setComponentType(type);
}
if (cookie?.includes('KIOSK')) {
fetchKiosk();
}
}, []);
const Component = AppLayout[componentType];
return (
<>
{Component && (
<Component pageProps={pageProps}>
<Pages {...pageProps} />
</Component>
)}
</>
)
}

此问题是由useState行为引起的;这种情况有点狡猾。

useState将函数作为参数来延迟初始化状态,并且传递React组件会触发该机制,因为React组件基本上是一个函数。

你可以通过两种方式解决这个问题:

(1( :使用函数返回使用中的函数状态:

const Layout = ({
Pages,
pageProps,
cookie
}) => {
const { setAppType, setAgentCookie } = useGlobalUI();
const [Component, setComponent] = useState(() => AppLayout[APP_TYPE.WEB]);
return (
<>
{Component ? (
<Component pageProps={pageProps}>
<Pages {...pageProps} />
</Component>
) : null}
</>
);
};

(2( :将APP_TYPE作为道具传递并解析useMemo:中的组件

const Layout = ({
Pages,
pageProps,
cookie,
someDynamicAppType = APP_TYPE.WEB`enter code here`
}) => {
const { setAppType, setAgentCookie } = useGlobalUI();
const Component = useMemo(() => AppLayout[someDynamicAppType], [
someDynamicAppType
]);
return (
<>
{Component ? (
<Component pageProps={pageProps}>
<Pages {...pageProps} />
</Component>
) : null}
</>
);
};

最新更新