Reputation: 1
I have a component that contains react-router-dom's Link
but throws the error below when I pass the component in the react-dom renderToString
Uncaught Error: useHref() may be used only in the context of a <Router> component.
Can't I pass a component that has react hooks into renderToString
functions?
import { renderToString } from 'react-dom/server';
const html = renderToString(<Contact />);
console.log(html);
Upvotes: 0
Views: 380
Reputation: 102257
I guess you use the useHref()
hook inside <Contact/>
component. But
useHref()
hook must be used in a Router context, the error throws at line lib/hooks.tsx#L36. Let's see the source code of useHref()
hook:
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 });
}
We can use <StaticRouter>
to do the SSR, StaticRouter
component uses Router component underly, Router
uses NavigationContext.Provider and LocationContext.Provider components to provide the context value to its children components, then you can use useHref()
hook in these children components.
Here is a working example:
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)
})
})
Test result:
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
package version:
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.8.1",
Upvotes: 0