Search code examples
javascriptreactjsmaterial-uireact-router-dom

I got "No routes matched location" Warning, when I update my "react-router-dom" from "5.2.0" to "6.14.0"


When I update react-router-dom from "5.2.0" to "6.14.0", I got a "No routes matched location" Warning.

At first I got Uncaught Error: A <Route> is only ever to be used as the child of <Routes> element, never rendered directly. Please wrap your <Route> in a <Routes>. So I put <Routes> under <BrowserRouter />. Then the error disappear, but the page is empty. I got "No routes matched location" Warning.

I also try to change the render to element and remove the "*" or "/". These doesn't work as well.

import React, { useEffect, useState } from "react";
import { createMuiTheme, MuiThemeProvider } from "@material-ui/core/styles";
import { ThemeProvider } from "@material-ui/styles";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import { useAppStyles } from "../xxxxx";

import ComponentOne from "../xxxxx";
import ComponentTwo from "../xxxxx";
import ComponentThree from "../xxxxx";
import ComponentFour from "../xxxxx";

const App = ({ config }) => {
  const classes = useAppStyles({});
  const [scopes, setScopes] = useState({});
  const [scopeError, setScopeError] = useState(false);

  useEffect(() => {
    httpService.init(config);
    userService.init(config);
    scopeService
      .getScopeConfig(config)
      .then((data) => setScopes(data))
      .catch(() => setScopeError(true));
  }, [config]);

  if (scopeError) {
    return <AppError message={SOMETHING_WENT_WRONG} />;
  } else if (isEmpty(scopes)) {
    return <Spinner className={classes.spinner} />;
  } else {
    const updatedConfig = { ...config, ...scopes };
    return (
      <MuiThemeProvider theme={theme}>
        <ThemeProvider theme={theme}>
          <ConfigContext.Provider value={updatedConfig}>
            <div className={classes.app}>
              <BrowserRouter>
                <Routes>
                  <Route path="*/component1" exact render={(props) => <ComponentOne {...props} />} />
                  <Route path="*/component2" exact render={(props) => <ComponentTwo {...props} />} />
                  <Route path="*/component3" exact render={(props) => <ComponentThree {...props} />} />
                  <Route path="*/component4" exact render={(props) => <ComponentFour {...props} />} />
                </Routes>
              </BrowserRouter>
            </div>
          </ConfigContext.Provider>
        </ThemeProvider>
      </MuiThemeProvider>
    );
  }
};

export default App;

Solution

  • The route paths should start with or without "/", remove the leading "*" character. react-router-dom@6 routes also now use only the element or Component prop to render content. element takes a React.ReactNode, i.e. JSX, value, and Component takes a React.ComponentType, i.e. a React component reference. Neither take a function. There is also no exact or render prop to be used.

    <BrowserRouter>
      <Routes>
        <Route path="/component1" element={<ComponentOne />} />
        <Route path="/component2" element={<ComponentTwo />} />
        <Route path="/component3" element={<ComponentThree />} />
        <Route path="/component4" element={<ComponentFour />} />
      </Routes>
    </BrowserRouter>
    

    Here's the entire Route component interface:

    interface RouteObject {
      path?: string;
      index?: boolean;
      children?: React.ReactNode;
      caseSensitive?: boolean;
      id?: string;
      loader?: LoaderFunction;
      action?: ActionFunction;
      element?: React.ReactNode | null;
      Component?: React.ComponentType | null;
      errorElement?: React.ReactNode | null;
      ErrorBoundary?: React.ComponentType | null;
      handle?: RouteObject["handle"];
      shouldRevalidate?: ShouldRevalidateFunction;
      lazy?: LazyRouteFunction<RouteObject>;
    }