Search code examples
javascriptreactjsreact-routerreact-router-dom

React Router how to use data returned from a loader


I am working on implementing a new React Router. I am using the new createBrowserRouter and want to implement some loader API calls. I have my project set up to make these API calls properly, however I can't find any docs on how to actually handle this data.

I want to pass the response data down to my component but it isn't clear how I do this.

I have an API folder with this network request.

export function getReasonTypes() {
  commonAxios
    .get('/api/ReasonTypes?activeOnly=true')
    .then(function (response) {
      console.log(response)
      return response.data
    })
    .catch(function (error) {
      console.log(error)
    })
}

I import this function when I create my router:

function defaulNewAPIs() {
  const data = getReasonTypes()
  return { data }
}

const router = createBrowserRouter([
  {
    path: '/:appTypeId?',
    element: <AppLayout />,
    loader: defaulNewAPIs,
    children: [
      {
        index: true,
        element: <ReferralDetails status="new" />,
      },
    ],
  },
])

ReactDOM.createRoot(document.getElementById('root')!).render(
  <GenReMsal>
    <React.StrictMode>
      <AuthenticatedTemplate>
        <RouterProvider router={router} />
      </AuthenticatedTemplate>
      <UnauthenticatedTemplate>
        <GenReLogin />
      </UnauthenticatedTemplate>
    </React.StrictMode>
  </GenReMsal>
)

The above code successfully calls my api, and based on the console log I can see it fetches data correctly. How do I pass this data into my router elements?


Solution

  • The getReasonTypes function needs to return a value for the defaulNewAPIs route loader function to return to the route component.

    • Return the Promise chain

      export function getReasonTypes() {
        return commonAxios // <-- return Promise to defaultNewAPIs
          .get('/api/ReasonTypes?activeOnly=true')
          .then(function (response) {
            console.log(response);
            return response.data; // <-- returned to getReasonTypes
          })
          .catch(function (error) {
            console.log(error);
            throw error;
          });
      }
      
    • Use async/await

      export async function getReasonTypes() {
        try {
          const response = await commonAxios.get('/api/ReasonTypes?activeOnly=true')
          console.log(response);
          return response.data; // <-- return value to defaultNewAPIs
        } catch(error) {
          console.log(error);
          throw error;
        };
      }
      

    The defaulNewAPIs loader function should wait for the resolved value returned by the getReasonTypes function.

    async function defaultNewAPIs() {
      const data = await getReasonTypes();
      return { data };
    }
    

    The component that you want to read the loaded route state should use either the useLoaderData

    import { useLoaderData } from 'react-router-dom';
    
    const AppLayout = () => {
      const data = useLoaderData();
    
      ...
    };
    

    or useRouteLoaderData hooks.

    const router = createBrowserRouter([
      {
        path: '/:appTypeId?',
        id: "root",
        element: <AppLayout />,
        loader: defaultNewAPIs,
        children: [
          {
            index: true,
            element: <ReferralDetails status="new" />,
          },
        ],
      },
    ])
    
    import { useRouteLoaderData } from "react-router-dom";
    
    const ReferralDetails = ({ status }) => {
      const data = useRouteLoaderData("root");
    
      ...
    }