Edit: Just to clarify the loader function itself runs correctly in the index route and returns the correct userData. However the data returned inside the component via useLoaderData is incorrect after the fetcher.submit calls.
As requested below is a link to a codeSandbox link that demonstrates the issue: CodeSandBox Link
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>
);
}
As I posted this as an issue on RR-github page as well. I got a more comprehensive answer there
But the answer is that GET requests do not trigger validation in react-router v6; only POST or mutations do.
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();
let fetcher = useFetcher();
let mostRecentData = fetcher.data || userData;
return (
<>
<div>
<RangePicker />
</div>
<div>
<User data={mostRecentData} />
</div>
</>
);
}