[英]Why does renderToString throws error about useLayoutEffect while rendering Material-UI component?
[英]How to fix "Warning: useLayoutEffect does nothing on the server" while using Material UI and reactDOMServer?
我遇到了 ReactDOMServer 和 Material UI Theme Provider 的问题。一切正常,但我在控制台上不断收到这个烦人的错误:
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.
到目前为止,我发现的所有解决方案都涉及我必须删除 ThemeProvider,但我想知道是否没有更好的方法来解决这个问题?
代码:
const mapIcon = useMemo(() => {
let namePosition: MapPinProps['namePosition'] = 'bottom-start';
if (position.lng > 120) {
namePosition = 'bottom-end';
}
if (position.lng > 120 && position.lat < -80) {
namePosition = 'top-end';
}
if (position.lng <= 120 && position.lat < -80) {
namePosition = 'top-start';
}
const html = ReactDOMServer.renderToStaticMarkup(
<ThemeProviders>
<MapPin
active={isMapBuilder ? active : !completed}
highlight={highlightRequiredEvent}
icon={completed && doneIcon ? doneIcon : icon}
name={event?.type !== EVENTS_TYPE.ANIMATION || isMapBuilder ? name : ''}
rarity={rarity}
read={isMapBuilder || event?.type === EVENTS_TYPE.ANIMATION || read}
interactive={isMapBuilder || event?.type !== EVENTS_TYPE.ANIMATION}
selected={selected}
shape={shape}
size={iconSize}
userSettings={user.settings}
namePosition={namePosition}
locked={locked && !isMapBuilder}
isMapBuilder={isMapBuilder}
/>
</ThemeProviders>
);
return new L.DivIcon({
className: '',
// iconAnchor,
// popupAnchor,
iconSize: [iconSize, iconSize],
html: html.toString(),
});
}, [
position.lng,
position.lat,
event?.type,
isMapBuilder,
active,
completed,
highlightRequiredEvent,
doneIcon,
icon,
name,
rarity,
read,
selected,
shape,
iconSize,
user.settings,
locked,
]);
我将尝试提供一些可以帮助解决该问题的选项。 我会在这里和那里做一些假设,让自己在某些情况下是错误的。
useLayoutEffect()
仅在 DOM 突变后触发。 通常,服务器没有适当的方法来处理它。 此外,官方文档还提到:
如果您使用服务器渲染,请记住,在下载 JavaScript 之前,useLayoutEffect 和 useEffect 都不能运行。 这就是为什么当服务器渲染的组件包含 useLayoutEffect 时 React 会发出警告。
并提供了一种修复它的方法,但它需要访问源代码(我想你没有)。
<ThemeProviders />
组件的源代码您可以尝试使用ReactDOMServer.renderToString()而不是ReactDOMServer.renderToStaticMarkup() 。
说明:假设您在服务器上使用它并在客户端上使用 React, 根据有关 ReactDOMServer.renderToStaticMarkup() 的官方文档:
如果您打算在客户端使用 React 来使标记交互,请不要使用此方法。 相反,在服务器上使用renderToString ,在客户端使用ReactDOM.hydraRoot() 。
ThemeProviders
组件源代码) 您可以更改对useLayoutEffect()
使用情况的检查,并阻止它在没有任何 DOM 的服务器上使用它。
说明:根据GitHub 问题中的此评论,它建议根据 DOM 的存在在useLayoutEffect()
和useEffect()
之间进行选择。 评论提到使用类似的东西:
const canUseDOM: boolean = !!(
typeof window !== 'undefined' &&
typeof window.document !== 'undefined' &&
typeof window.document.createElement !== 'undefined'
);
const useIsomorphicLayoutEffect = canUseDOM ? useLayoutEffect : useEffect;
你可以在你的组件中使用这个useIsomorphicLayoutEffect()
。
您可以考虑删除ReactDOMServer
的使用。
说明:这似乎是一个非常简单的组件,与服务器渲染相比,选择在客户端渲染它的成本可能微不足道。 注意:在选择删除 SSR 之前,您可以根据一些基准和测试做出此决定。
我希望其中一些可以帮助你!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.