I am trying to implement a protected route by checking if the user is signed in. I am using React 18, Typescript, and React Router v6.
However, it keeps on complaining 'Navigate' refers to a value, but is being used as a type here. Did you mean 'typeof Navigate'?ts(2749)
import { Navigate } from "react-router-dom";
interface Props {
children?: ReactNode;
}
const Protected = ({ children }: Props) => {
if (isSignedIn) {
return <Navigate to="/" />;
}
return children;
};
export default Protected;
It seems like there's some issue with your node_modules. You may want to remove the folder entirely then re-run npm ci
or yarn install --frozen-lockfile
. You can also remove those lock files and just do a yarn install
or npm install
from scratch.
Consider this barebones approach instead with a working sandbox example - flip const isSignedIn = true;
and test the /secret
path.
package.json
{
"name": "react",
"version": "1.0.0",
"description": "React example starter project",
"keywords": [
"react",
"starter"
],
"dependencies": {
"@types/jest": "^29.4.0",
"@types/node": "^18.13.0",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.10",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-router-dom": "^6.8.1",
"react-scripts": "^5.0.1",
"typescript": "^4.9.5"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
]
}
tsconfig.json
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"allowJs": false,
"skipLibCheck": true,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"moduleResolution": "Node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"baseUrl": "."
},
"include": ["src"]
}
index.tsx
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
const rootElement = document.getElementById("root");
const root = createRoot(rootElement as HTMLElement);
root.render(
<StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</StrictMode>
);
App.tsx
import { Route, Routes as RouteSwitch } from "react-router-dom";
import Protected from "./Protected";
const PublicComponent = () => <span>hello world</span>;
const SecretComponent = () => <span>hello darkness my old friend</span>;
export default function App() {
return (
<div>
<RouteSwitch>
<Route path="/" element={<PublicComponent />} />
<Route
path="/secret"
element={
<Protected>
<SecretComponent />
</Protected>
}
/>
</RouteSwitch>
</div>
);
}
Protected.tsx
import { FC, ReactNode, useEffect } from "react";
import { useNavigate } from "react-router-dom";
interface Props {
children?: ReactNode;
}
const isSignedIn = true;
const Protected: FC<{ children: ReactNode }> = ({ children }: Props) => {
const navigate = useNavigate();
useEffect(() => {
if (!isSignedIn) navigate("/");
}, [isSignedIn]);
return <>{children}</>;
};
export default Protected;