- I am using a simple vite react.js (v18) app client app with react router v6.
- In react router dom version 6.22.3, I am using useFetcher’s fetcher.Form component and calling fetcher.submit on change inside the form.
- This successfully changed the request params and the loader function of the parent route for the component is called again.
- However the useLoaderData in that route still returns the old data to child components.
Below is the create router:
const router = createBrowserRouter([
{
path: '/',
element: <Root />,
errorElement: <ErrorPage />,
children: [
{ index: true, element: <Index />, loader: indexLoader },
],
}
]);
const rootElement = document.getElementById('root');
if (rootElement) {
ReactDOM.createRoot(rootElement).render(
<React.StrictMode>
<RouterProvider router={router} />
</React.StrictMode>
);
} else {
console.error("Element with ID 'root' not found in the document");
}
then the index route:
import RangePicker from '../components/rangePicker';
export async function loader({ request }) {
const url = new URL(request.url);
const startDate = url.searchParams.get('startDate');
const endDate = url.searchParams.get('endDate');
// This gets called correctly on every fetcher.submit();
const userData = await getUserData(startDate, endDate);
return { userData };
}
export default function Index() {
// userData if logged gets called once with new data, but
// after that gets called again with old data
const { userData } = useLoaderData();
return (
<>
<div>
<RangePicker />
</div>
<div>
<User data={userData} />
</div>
</>
);
}
Below is the RangePicker component:
import { addDays } from 'date-fns';
import { useState } from 'react';
import { DateRangePicker } from 'react-date-range';
import { useFetcher } from 'react-router-dom';
export default function RangePicker() {
const [state, setState] = useState([
{
startDate: new Date(),
endDate: addDays(new Date(), 7),
key: 'selection',
},
]);
const fetcher = useFetcher();
const handleDateRangeChange = (item) => {
setState([item.selection]);
const startDate = item.selection.startDate;
const endDate = item.selection.endDate;
//successfully triggers the loader for parent, but useLoaderData
// still returns previous data.
fetcher.submit(
{ startDate, endDate }
);
};
return (
<fetcher.Form>
<DateRangePicker
onChange={handleDateRangeChange}
moveRangeOnFirstSelection={false}
ranges={state}
/>
</fetcher.Form>
);
}