是否可以在将使用 renderToString 呈现的组件中使用反应钩子

问题描述 投票:0回答:1

我有一个包含 react-router-dom 的组件

Link
但是当我在 react-dom 中传递组件时抛出下面的错误
renderToString

Uncaught Error: useHref() may be used only in the context of a <Router> component.

我不能将具有 React 钩子的组件传递到

renderToString
函数中吗?

import { renderToString } from 'react-dom/server';

  const html = renderToString(<Contact />);
  console.log(html);
reactjs react-hooks react-dom react-dom-server render-to-string
1个回答
0
投票

我猜你在

useHref()
组件中使用了
<Contact/>
钩子。但
useHref()
钩子必须在 Router 上下文中使用,错误在 lib/hooks.tsx#L36 行抛出。来看看
useHref()
钩子的源码:

export function useHref(to: To): string {
  invariant(
    useInRouterContext(),
    // TODO: This error is probably because they somehow have 2 versions of the
    // router loaded. We can help them understand how to avoid that.
    `useHref() may be used only in the context of a <Router> component.`
  );

  let { basename, navigator } = React.useContext(NavigationContext);
  let { hash, pathname, search } = useResolvedPath(to);

  let joinedPathname = pathname;
  if (basename !== "/") {
    let toPathname = getToPathname(to);
    let endsWithSlash = toPathname != null && toPathname.endsWith("/");
    joinedPathname =
      pathname === "/"
        ? basename + (endsWithSlash ? "/" : "")
        : joinPaths([basename, pathname]);
  }

  return navigator.createHref({ pathname: joinedPathname, search, hash });
}

我们可以使用

<StaticRouter>
做SSR,
StaticRouter
组件使用底层的Router组件,
Router
使用NavigationContext.ProviderLocationContext.Provider组件为其子组件提供上下文值, 然后你可以在这些子组件中使用
useHref()
钩子。

这是一个工作示例:

import React from 'react';
import { renderToString } from 'react-dom/server';
import { describe, it } from "@jest/globals";
import { Routes, Route, useHref } from 'react-router-dom';
import { StaticRouter } from 'react-router-dom/server';

const Contact = ({ to }) => {
  const href = useHref(to)
  return <pre>{href}</pre>
}

describe('76209110', () => {
  it('should pass', () => {
    const html = renderToString(
      <StaticRouter location={'/courses'}>
        <Routes>
          <Route
            path="courses"
            element={<Contact to="advanced-react" />}
          />
        </Routes>
      </StaticRouter>
    )
    console.log('html: ', html)
  })
})

测试结果:

  console.log
    html:  <pre>/courses/advanced-react</pre>

      at Object.<anonymous> (stackoverflow/76209110/index.test.tsx:24:13)

 PASS  stackoverflow/76209110/index.test.tsx
  76209110
    ✓ should pass (66 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        2.42 s

包装版本:

"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.8.1",
© www.soinside.com 2019 - 2024. All rights reserved.