如何修复和报价“警告:uselayouteffect在服务器上无能为力”。在使用材料UI和ReactDomserver时?

发布于 2025-02-11 14:33:07 字数 2213 浏览 1 评论 0 原文

我对ReactDomserver和Material UI主题提供商有一个问题。.一切正常 Fine ,但我一直在控制台上遇到这个烦人的错误:

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.

到目前为止,我发现的所有解决方案都涉及我删除theaseprovider,但我想知道是否没有更好的解决方案?

代码:

  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,
  ]);

I'm having a issue with ReactDOMServer and Material UI Theme Provider.. Everything is working just fine but I keep getting this annoying error on console:

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.

All the solutions I've found so far involve me having to remove ThemeProvider, but I would like to know if there is no way better to solve this?

CODE:

  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,
  ]);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

也只是曾经 2025-02-18 14:33:08

我将尝试提供一些可以帮助解决这个问题的选择。我将在这里和那里做一些假设,在某些情况下让自己错了。

上下文

uselayouteffect(useLayouteffect() 。通常,服务器没有适当的处理方式。此外,官方文档还提到:

如果您使用服务器渲染,请记住,在下载JavaScript之前,uselayouteffect均无法运行。这就是为什么当服务器渲染的组件包含USELAYOUTEFFECT时,反应警告。

并提供一种修复它的方法,但它需要访问源代码(我想您没有)。

假设

  • 您正在使用服务器端渲染以在后端构建组件的
  • ,您也在客户端(frontend)使用react(frontend)
  • 您正在使用feaflet进行映射(因为 l.divicon()
  • 您无法访问更改&lt; thealeproviders/&gt; 组件

可能解决方案的源代码#1(可能是最好的吗?)

您可以尝试使用 reactdomserver.renderver.renderter.rendertertostostostostostostostostostostostostring() >代替 reactdomserver.rendertostaticmarkup()

说明:假设您在服务器上使用它并在客户端上使用React,

如果您打算在客户端上使用React来制作标记交互式,请不要使用此方法。而是使用 rendertostrer“> rendertostring 在服务器上和 reactdom.hydrateroot()在客户端。

可能的解决方案#2(访问 themeproviders 组件源代码)

您可以更改使用 uselayouteffect()的使用的支票,并防止其在服务器上使用它您没有任何DOM。

说明:根据 UseLayouteffect()和 useeffect()之间选择。评论提及使用类似的内容:

const canUseDOM: boolean = !!(
  typeof window !== 'undefined' &&
  typeof window.document !== 'undefined' &&
  typeof window.document.createElement !== 'undefined'
);

const useIsomorphicLayoutEffect = canUseDOM ? useLayoutEffect : useEffect;

您可以在组件内使用此 usemorphiclayouteffect()

可能的解决方案#3(不使用SSR)

您可以考虑删除 reactdomserver 的使用。

说明:这似乎是一个非常简单的组件,与服务器渲染相比,选择在客户端上渲染它的成本可能微不足道。 注意:选择删除SSR之前,您可以将此决定基于一些基准和测试。


我希望其中一些可以帮助您!

I'll try to give some options that could help on solving that. I'll make some assumptions here and there, allowing myself to be wrong in some cases.

Context

useLayoutEffect() only fires after DOM mutations. In general, servers don't have a proper way of handling that. Also, the official doc also mentions:

If you use server rendering, keep in mind that neither useLayoutEffect nor useEffect can run until the JavaScript is downloaded. This is why React warns when a server-rendered component contains useLayoutEffect.

and gives a way of fixing it but it requires access to the source code (which I suppose you don't have).

Assumptions

  • You are using Server Side Rendering to build Components at the Backend
  • You are also using React at the Client (Frontend)
  • You are using Leaflet for Maps (because L.DivIcon())
  • You don't have access to change the source code of the <ThemeProviders /> component

Possible Solution #1 (Possibly best one?)

You could try to use ReactDOMServer.renderToString() instead of ReactDOMServer.renderToStaticMarkup().

Explanation: Supposing that you are using this on the server and using React on the Client, according to the official docs about ReactDOMServer.renderToStaticMarkup():

If you plan to use React on the client to make the markup interactive, do not use this method. Instead, use renderToString on the server and ReactDOM.hydrateRoot() on the client.

Possible Solution #2 (With access to ThemeProviders component source code)

You could change the check for the usage of useLayoutEffect() and prevent it from using it at the server, where you don't have any DOM.

Explanation: According to this comment inside an Issue at GitHub, it suggest choosing between useLayoutEffect() and useEffect() based on the existence of the DOM. The comment mention about using something like:

const canUseDOM: boolean = !!(
  typeof window !== 'undefined' &&
  typeof window.document !== 'undefined' &&
  typeof window.document.createElement !== 'undefined'
);

const useIsomorphicLayoutEffect = canUseDOM ? useLayoutEffect : useEffect;

And you could use this useIsomorphicLayoutEffect() inside your component.

Possible Solution #3 (not use SSR)

You could consider removing the usage of the ReactDOMServer.

Explanation: This seems to be a very simple component and the cost of choosing to render it on Client could be insignificant compared to the server render. NOTE: Before choosing to remove the SSR you could base this decision on some benchmarks and tests.


I hope that some of this could help you!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文