Search code examples
reactjstypescriptreact-routerreact-router-domremix.run

react-router v6 createRouterBrowser


I am trying to implement react-router in my app. I saw there is now data loading possible within the routing therefore I had to use the createBrowserRouter. I seem to not fully understand how it is done correctly.

My set up until now was I have a index.tsx file :

import React from 'react';
import { createRoot } from 'react-dom/client';
import { Provider } from 'react-redux';
import { store } from './app/store';
import App from './App';
import reportWebVitals from './reportWebVitals';
import './index.css';
import {createBrowserRouter, Route, RouterProvider} from 'react-router-dom';
import {ExpressionOverviewPage, expressionLoader} from "./features/expressionoverviewpage/ExpressionOverviewPage";

const container = document.getElementById('root')!;
const root = createRoot(container);

const router = createBrowserRouter([
  {
    path: "/",
    element: <App />,
    children: [
      {
        path: "/",
        element: <Route element={<ExpressionOverviewPage />} />
      },
      {
        path: "/:geneID",
        element: <ExpressionOverviewPage />,
        loader: expressionLoader
      }
    ]
  },
]);

root.render(
  <React.StrictMode>
    <Provider store={store}>
      <RouterProvider router={router}>
        <App />
      </RouterProvider>
    </Provider>
  </React.StrictMode>
);

reportWebVitals();

In the index.tsx I am calling the file App.tsx:

import React from "react";
import { Amplify, API, graphqlOperation } from "aws-amplify";
import {
  ThemeProvider,
  Authenticator,
  Button,
  Flex,
  Image,
  Text,
  useTheme,
  View,
} from "@aws-amplify/ui-react";
import aws_exports from "./aws-exports";
import "@aws-amplify/ui-react/styles.css";
import theme from "./theme";
import logo from "./logo.svg";
import { useAppSelector } from "./app/hooks";
import { selectUser } from "./features/auth/authSlice";
import { ErrorPage } from './features/errorpage/ErrorPage';
import {
  Routes,
  Route,
  NavLink,
  useSearchParams,
  BrowserRouter
} from 'react-router-dom';
import "./styles.css"
import { ExpressionOverviewPage } from "./features/expressionoverviewpage/ExpressionOverviewPage";
import { GeneNameAutoComplete } from "./features/GeneNameAutoComplete/GeneNameAutoComplete"
import { ScoresTable } from "./features/scorestable/ScoresTable";
import { GraphQLQuery } from "@aws-amplify/api";
import { DataPoint, GetViolinDataQuery } from "./API";
import { getViolinData } from "./graphql/queries";

Amplify.configure(aws_exports);

const components = {
  Header() {
    const { tokens } = useTheme();

    return (
      <View textAlign="center" padding={tokens.space.large}>
        <img src={logo} className="App-logo" alt="logo" width={400} />
      </View>
    );
  }
}

const App = () => {
  const store_user = useAppSelector(selectUser);

  return (
    <ThemeProvider theme={theme}>
      <Authenticator
        hideSignUp={true}
        components={components}
      >
        {({ signOut, user }) => (
          <Flex
            direction="column"
            justifyContent="space-evenly"
            alignItems="flex-start"
            alignContent="flex-start"
            wrap="nowrap"
            gap="1rem"
            textAlign="center"
            width="100%"
            padding="10px"
          >
            <Flex
              direction="row"
              justifyContent="space-between"
              width="100%"
            >
              <Image src={logo} alt="logo" width={200} />
              {user && (
                <View>
                  <Button onClick={signOut}>
                    <Text>Sign Out {store_user}</Text>
                  </Button>
                </View>
              )}
            </Flex>
          </Flex>
        )}
      </Authenticator>
    </ThemeProvider>
  );
};

export default App;

For this line <Provider store={store}> in the index.tsx I get following warning:

TS2322: Type '{ children: Element; router: Router; }' is not assignable to type 'IntrinsicAttributes & RouterProviderProps'.
Property 'children' does not exist on type 'IntrinsicAttributes & RouterProviderProps'.

I dont understand what should be the issue there. The other thing is that I am wondering how I need to change my architecture in order to get createBrowserRouter running. I think I add the browserRouter at the right place but I think I will have to do something differently with my app.tsx file.

I want to have react-router working in my app. The goal will be to have an id passed in the url and the loader fetching the data before rendering. I try to get there with baby steps one after the other but already at the beginning I get the warning which I did not expect.


Solution

  • The RouterProvider takes no children prop.

    declare function RouterProvider(
      props: RouterProviderProps
    ): React.ReactElement;
    
    interface RouterProviderProps {
      fallbackElement?: React.ReactNode;
      router: Router;
      future?: FutureConfig;
    }
    

    App is rendered on one of the routes in router, so remove it as a child component of RouterProvider.

    const router = createBrowserRouter([
      {
        path: "/",
        element: <App />, // <-- App rendered here
        children: [
          {
            index: true,
            element: <Route element={<ExpressionOverviewPage />} />
          },
          {
            path: "/:geneID",
            element: <ExpressionOverviewPage />,
            loader: expressionLoader
          }
        ]
      },
    ]);
    
    root.render(
      <React.StrictMode>
        <Provider store={store}>
          <RouterProvider router={router} />
        </Provider>
      </React.StrictMode>
    );