React Router 6 useLoaderData возвращает кэшированные данные

  • Я использую простое клиентское приложение vite act.js (v18) с маршрутизатором React v6.
  • В ответном маршрутизаторе dom версии 6.22.3 я использую компонент useFetcher fetcher.Form и вызываю fetcher.submit при изменении внутри формы.
  • Это успешно изменило параметры запроса, и функция загрузчика родительского маршрута для компонента вызывается снова.
  • Однако useLoaderData в этом маршруте по-прежнему возвращает старые данные дочерним компонентам.

Редактировать: Просто чтобы прояснить, сама функция загрузчика работает правильно в индексном маршруте и возвращает правильные пользовательские данные. Однако данные, возвращаемые внутри компонента через useLoaderData, неверны после вызовов fetcher.submit.

В соответствии с просьбой ниже приведена ссылка на ссылку codeSandbox, которая демонстрирует проблему: Ссылка на CodeSandBox

Ниже показано создание маршрутизатора:

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");
}

затем индексный маршрут:

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>
        </>
    );
}

Ниже приведен компонент RangePicker:

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>
    );
}

Вы хотите сказать, что загрузчик индексного маршрута правильно извлекает правильное значение userData из getUserData, т. е. значение userData — это то, что вы ожидаете после отправки и повторной проверки маршрута, но каким-то образом возвращает неправильное значение userData обратно в компонент? Можете ли вы отредактировать, чтобы прояснить проблему и предоставить более четкие сведения об отладке?

Drew Reese 29.04.2024 18:07

Это правильно @DrewReese. Я могу добавить это туда.

Nosh 30.04.2024 01:39

Это очень интересно. Не могли бы вы создать работающую демо-версию Codesandbox, воспроизводящую такое поведение, которое мы могли бы проверить вживую?

Drew Reese 30.04.2024 01:42

@DrewReese, как и просили, я предоставил пример CodeSandbox, чтобы продемонстрировать проблему. Надеюсь, поможет.

Nosh 01.05.2024 13:06

Хук @Nosh useLoaderData предоставляет последнее значение, возвращаемое вашей функцией загрузчика маршрута, и он не запускается, когда форма отправляется с помощью сборщика. См. этот выпуск на Github

Amit 01.05.2024 14:21

Спасибо @Amit, я также разместил это на Github и получил подробный ответ. Короче говоря, запросы Get не вызывают повторную проверку, а запросы POST или мутации. Решение состоит в том, чтобы получить мутированные данные из средства выборки в маршруте родительского индекса и объединить их. Я опубликую ответ более подробно по этой проблеме на GitHub: github.com/remix-run/react-router/issues/11518

Nosh 02.05.2024 01:03
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
1
6
247
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Поскольку я также разместил это как проблему на странице RR-github. Более развернутый ответ я получила там

Но ответ заключается в том, что запросы GET не запускают проверку в маршрутизаторе реакции v6; только POST или мутации.

  • Решение состоит в том, чтобы использовать в форме метод = 'post'.
  • не вызывайте PreventDefault() в ChangeHandler, так как это не отправит метод запроса.
  • А затем вызовите useFetcher в маршруте родительского индекса и объедините данные, возвращенные из useLoaderData.
  • Ниже код не проверен, но показывает разрешение
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>
        </>
    );
}

 

Другие вопросы по теме