redux 为什么createAsyncThunk承诺要查找“isBatchingLegacy”?

vecaoik1  于 2022-11-24  发布在  其他
关注(0)|答案(1)|浏览(252)

我在尝试使用redux的新方法时遇到了一个令人沮丧的问题。我一直在遵循https://redux-toolkit.js.org/上的指南/文档/教程,但无论我尝试什么,我总是遇到同样的问题。

错误消息

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'isBatchingLegacy')
    at batchedUpdates$1 (react-dom.development.js:4441:25)
    at Object.notify (Subscription.js:20:7)
    at Object.notifyNestedSubs (Subscription.js:78:15)
    at handleChangeWrapper (Subscription.js:82:20)
    at dispatch (redux.js:276:7)
    at eval (redux-toolkit.esm.js:547:22)
    at eval (index.js:23:16)
    at eval (redux-toolkit.esm.js:461:32)
    at dispatch (redux.js:623:28)
    at eval (redux-toolkit.esm.js:1488:21)

内容:

"@reduxjs/toolkit": "^1.9.0",
    "axios": "^1.1.3",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-redux": "^8.0.5",
    "react-router-dom": "^6.4.3"

我尝试将一个简单API调用的结果放入redux存储中。

源代码/组件/应用程序/用户切片.ts

import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import axios from 'axios';
import { User } from '@componentLib/path/to/my/types/User';

interface UserState {
  status: string;
  user: User | {};
}
const initialState: UserState = {
  status: 'idle',
  user: {},
};

// async thunk
export const getUser = createAsyncThunk<User, void>(
  'user/getUser',
  async () => {
      console.log('fetching user...'); // this is never called
      const { data: user } = await axios.get('/api/user');
      console.log('user response', user); // this is never called
      return user as User;
  },
);

// core redux state slice for users
export const userSlice = createSlice({
  name: 'user',
  initialState,
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(getUser.pending, (state, action) => {
        console.log('pending', action);
        state.status = 'loading';
      })
      .addCase(getUser.fulfilled, (state, action) => {
        console.log('fulfilled', action);
        state.user = action.payload;
        state.status = 'idle';
      });
  },
});

// basic selector to return user
export const selectUser = (state: any) => state.user.user;
export const selectStatus = (state: any) => state.user.status;

// export the reducer
export default userSlice.reducer;

源代码/组件/应用程序/应用程序.tsx

import { Suspense, lazy, useEffect, useState } from 'react';
import { useAppSelector, useAppDispatch } from '../../hooks';

import axios from 'axios';
import { MyApp } from '@componentLib/myApp';

import { getUser, selectStatus, selectUser } from './userSlice';
import ErrorBoundary from '../ErrorBoundary';
import Authenticating from './Authenticating';

const ExampleModule = lazy(() => import('exampleModule/ExampleModule'));

function App() {
  const example = (
    <ErrorBoundary>
      <Suspense fallback={<>Loading...</>}>
        <ExampleModule />
      </Suspense>
    </ErrorBoundary>
  );

  // const [user, setUser] = useState(); // old way that used to work prior to redux
  const user = useAppSelector(selectUser);
  const status = useAppSelector(selectStatus);
  const dispatch = useAppDispatch();

  useEffect(() => {
    // old way that used to work prior to redux implementation
    // a.k.a what I'm trying to replace so sub components have access to the user via redux 
    // rather than as a passed prop (like below)
    const getUserOld = async () => {
      const { data: user } = await axios.get('/api/user');
      console.log('non-thunk load', user);
      // if (user.sid) {
      //   console.log("user", user);
      //   // setUser(user);
      // } else {
      //   // redirect them to authenticate via OIDC/SSO
      //   // window.location.replace('/api/auth');
      // }
    };
    getUserOld();

    console.log('dispatching get user');
    dispatch(getUser());
  }, []);

  useEffect(() => {
    // If the user is not defined and the loader is not fetching
    console.log('status', status);
    console.log('user', user);
  }, [status, user]);

  const modules = [
    {
      path: '/',
      name: 'Example',
      element: example,
    },
  ];
  return user.sid ? (
    <MyApp modules={modules} user={user} />
  ) : (
    <Authenticating />
  );
}

export default App;

源代码/存储.ts

import { configureStore } from '@reduxjs/toolkit';
import userReducer from './components/App/userSlice';

export const store = configureStore({
  reducer: {
    user: userReducer,
  },
});

// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>;
// Inferred type: {users: UsersState} ect...
export type AppDispatch = typeof store.dispatch;

export default store;

源代码/钩子.ts

import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
import type { RootState, AppDispatch } from './store';

// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch: () => AppDispatch = useDispatch;
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;

/源代码/索引.tsx

import { createRoot } from 'react-dom/client';
import { Provider } from 'react-redux';
import App from './components/App';
import { store } from './store';

const container = document.getElementById('app');
const root = createRoot(container);

root.render(
  <Provider store={store}>
    <App />
  </Provider>,
);

这将生成以下控制台日志:

[HMR] Waiting for update signal from WDS...
App.tsx:94 dispatching get user
userSlice.ts:81 pending {type: 'user/getUser/pending', payload: undefined, meta: {…}}
App.tsx:99 status idle
App.tsx:100 user {}
App.tsx:99 status loading
App.tsx:100 user {}
react-dom.development.js:4441 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'isBatchingLegacy')
non-thunk load {sid: 'A123456', firstName: 'CLEAN', lastName: 'SHOOTER', roles: Array(5)}

正如你所看到的,这个设置的大部分内容都是从redux工具包网站上逐字逐句地得到的。它似乎在thunk试图执行承诺的时候失败了,但我不知道为什么。我也不是一个 typescript Maven,所以看到一个我没有使用的名为“isBatchingLegacy”的变量被查找是令人困惑的。这让我相信我还没有“t正确地键入了createAsyncThunk,但我试着尽我所能遵循redux网站上的文档。如果你需要更多的信息或额外的上下文,请让我知道。

q9rjltbz

q9rjltbz1#

您的应用程序代码看起来没有问题。根据实际的错误消息堆栈跟踪,它来自react-dom内部,实际上不是Redux Toolkit的问题。
也就是说,我不知道 * 为什么 * React中会发生错误。我认为你怀疑模块联邦 * 以某种方式 * 参与其中是正确的,但我不知道这里的问题到底是什么。

相关问题