TypeError: store.dispatch не является функцией

Я следую Руководству по тестированию на написание Redux, чтобы протестировать свое приложение Redux/TypeScript. Я столкнулся с ошибкой TypeError: store.dispatch is not a function.

Я последовал этому предложению по экспорту и использованию уже настроенного объекта хранилища, но все равно получаю сообщение об ошибке. Что мне не хватает?

(моя попытка)

export default function setupStore(preloadedState?: PreloadedState<RootState>) {
    return configureStore({
        reducer: persistedReducer,
        middleware: (getDefaultMiddleware) =>
            getDefaultMiddleware({
                serializableCheck: {
                    ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
                },
            }),
        preloadedState,
    });
};

Вот файлы с соответствующим кодом.

test-utils.tsx

import setupStore from '../store';

interface ExtendedRenderOptions extends Omit<RenderOptions, 'queries'> {
    preloadedState?: PreloadedState<RootState>;
    store?: AppStore;
}

export function renderWithProviders(
    ui: React.ReactElement,
    {
        preloadedState = {},
        store = setupStore(preloadedState),
        ...renderOptions
    }: ExtendedRenderOptions = {},
) {
    function Wrapper({ children }: PropsWithChildren<{}>): JSX.Element {
        return <Provider store = {store}>{children}</Provider>;
    }

    return { store, ...render(ui, { wrapper: Wrapper, ...renderOptions }) };
}

store.ts

const persistConfig = {
    key: 'root',
    version: 1,
    storage,
};

const rootReducer = combineReducers({ user: userReducer, cart: cartReducer });
const persistedReducer = persistReducer(persistConfig, rootReducer);
export default function setupStore(preloadedState?: PreloadedState<RootState>) {
    return configureStore({
        reducer: persistedReducer,
        middleware: (getDefaultMiddleware) =>
            getDefaultMiddleware({
                serializableCheck: {
                    ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
                },
            }),
        preloadedState,
    });
};

export let persistor = persistStore(setupStore as any);
export type RootState = ReturnType<typeof rootReducer>;
export type AppStore = ReturnType<typeof setupStore>;
export type AppDispatch = AppStore['dispatch'];

Navbar.tsx

const Navbar: React.FC = () => {
    const cartQuantity = useAppSelector((state: RootState) => state.cart.cartQuantity);
    const { currentUser } = useAppSelector((state: RootState) => state.user);

    return (
        <Language>EN</Language>
    );
};

Navbar.test.tsx

it('renders same span text in Navbar component', async () => {
    renderWithProviders(<Navbar />);
    const spanElement = screen.getByText(/EN/i);
    expect(spanElement).toBeInTheDocument();
});
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
0
70
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Я думаю, что вы столкнулись с той же проблемой, что и сообщение, на которое вы ссылались, с функцией setupStore, и вам нужно вызвать ее, чтобы получить реальный объект store.

AppDispatch должен быть typeof store.dispatch. Попробуйте следующее, где AppDispatch «выбирается» из типа AppStore.

store.ts

export default function setupStore(preloadedState?: PreloadedState<RootState>) {
  return configureStore({
    reducer: persistedReducer,
    middleware: (getDefaultMiddleware) =>
      getDefaultMiddleware({
        serializableCheck: {
          ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
        },
      }),
    preloadedState,
  });
};

export type RootState = ReturnType<typeof rootReducer>;
export type AppStore = ReturnType<typeof setupStore>;
export type AppDispatch = Pick<AppStore, "dispatch">;

index.tsx — импортируйте setupStore и persistStore сюда и создайте экземпляры storepersistor объектов.

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import { Provider } from "react-redux";
import { PersistGate } from "redux-persist/integration/react";
import persistStore from "redux-persist/es/persistStore";
import setupStore from "./store";

const store = setupStore();
const persistor = persistStore(store);

ReactDOM.render(
  <Provider store = {store}>
    <PersistGate loading = {null} persistor = {persistor}>
      <App />
    </PersistGate>
  </Provider>,
  document.getElementById("root")
);

Я ценю ваш ответ. Я пытался export type AppDispatch = typeof setupStore.dispatch и export type AppStore = ReturnType<typeof setupStore>;, но, к сожалению, все еще получаю ту же ошибку.

ln09nv2 02.02.2023 08:55

@ ln09nv2 Понятно. Я пробовал вышеописанное в проекте, который я нахожусь в процессе перехода на использование RTK, и экспорт этих типов имел ту же подпись, что и мой обычный экспорт export type AppDispatch = typeof store.dispatch;, поэтому он выглядел эквивалентным. Как вы думаете, вы могли бы создать работающую демонстрацию codeandbox вашего кода, которая воспроизводит проблему, которую мы могли бы проверить вживую?

Drew Reese 02.02.2023 09:00

Мне не удалось импортировать весь мой проект в CodeSandbox, так как я достиг максимального предела в 500 модулей. Вместо этого я вручную скопировал/вставил соответствующие файлы, чтобы воспроизвести проблему. Вот так

ln09nv2 03.02.2023 05:53

@ ln09nv2 Код в вашей песочнице (и, вероятно, реальный код, на котором он основан) не компилировался, потому что вы не передавали фактический store объект в persistStore функцию. Переместите создание persistor в index.ts, где вы должны создать экземпляр объекта store, который будет передан компоненту Redux Provider и persistor в PersistGate. Я обновил свой ответ и включил рабочую вилку вашей песочницы.

Drew Reese 03.02.2023 07:23

Это сработало! Я был смущен передачей фактического объекта хранилища при следовании руководству. Спасибо!

ln09nv2 05.02.2023 07:37

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