Redux-Saga: TypeError: Cannot read properties of undefined (reading 'data')

Redux-Saga: TypeError: Cannot read properties of undefined (reading 'data')

我正在尝试 运行 我的 Redux 应用程序与 redux-saga。

基本上我的 store.js 我有以下代码:

import { applyMiddleware, createStore } from "redux";
import createSagaMiddleware from "redux-saga";
import logger from "redux-logger";

import rootReducer from "./reducers/rootReducer";
import rootSaga from "./sagas/userSagas";

const sagaMiddleware = createSagaMiddleware();

const middleware = [sagaMiddleware];

if (process.env_NODE_ENV === "development") {
  middleware.push(logger);
}

const store = createStore(rootReducer, applyMiddleware(...middleware));

sagaMiddleware.run(rootSaga);

export default store;

我的 usersApi.js 看起来像这样:

import axios from "axios";

export const loadUsersApi = async () => {
  await axios.get("http://localhost:5000/users");
};

这是我的 userSagas:

import * as type from "../actionType";

import {
  take,
  takeEvery,
  takeLatest,
  put,
  all,
  delay,
  fork,
  call,
} from "redux-saga/effects";

import { loadUsersSuccess, loadUsersError } from "../actions/userAction";
import { loadUsersApi } from "../services/userApi";

export function* onLoadUsersStartAsync() {
  try {
    const response = yield call(loadUsersApi);
    if (response.status === 200) {
      yield delay(500);
      yield put(loadUsersSuccess(response.data));
    }
  } catch (error) {
    yield put(loadUsersError(error.response.data));
  }
}

export function* onLoadUsers() {
  yield takeEvery(type.LOAD_USERS_START, onLoadUsersStartAsync);
}

const userSagas = [fork(onLoadUsers)];

export default function* rootSaga() {
  yield all([...userSagas]);
}

当我 运行 在我的 HomePage.js 文件中加载和发送数据时:

import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { loadUsersStart } from "../redux/actions/userAction";

export default function HomePage() {
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(loadUsersStart());
  }, [dispatch]);

  return (
    <div>
      <h1>Home</h1>
    </div>
  );
}

它给了我这个错误:

[HMR] Waiting for update signal from WDS...
index.js:1 TypeError: Cannot read properties of undefined (reading 'data')
    at onLoadUsersStartAsync (userSagas.js:25)
    at onLoadUsersStartAsync.next (<anonymous>)
    at next (redux-saga-core.esm.js:1157)
    at currCb (redux-saga-core.esm.js:1251)

index.js:1 The above error occurred in task onLoadUsersStartAsync
    created by takeEvery(LOAD_USERS_START, onLoadUsersStartAsync)
    created by onLoadUsers
    created by rootSaga
Tasks cancelled due to error:
takeEvery(LOAD_USERS_START, onLoadUsersStartAsync)

我不确定是什么导致了这个错误,但即使是我的应用程序的记录器也没有显示正在调度的操作。

知道如何解决这个问题吗?

你需要return

的承诺
export const loadUsersApi = () => {
  return axios.get("http://localhost:5000/users");
};

也许下次尝试使用打字稿。它会防止你犯类似的错误

或者,您可以在不使用 redux-saga 的情况下构建 redux

我通常是这样设置它们的:-

一个。减速机
  • /slices/auth.js
import { createSlice } from '@reduxjs/toolkit'

const initialState = {
  users: [],
  loading: false,
  success: false,
  error: false,
  message: ''
}

export const usersSlice = createSlice({
  name: 'users',
  initialState,
  // // The `reducers` field lets us define reducers and generate associated actions
  reducers: {
    setUsers: (state, action) => {
      // Redux Toolkit allows us to write "mutating" logic in reducers. It
      // doesn't actually mutate the state because it uses the Immer library,
      // which detects changes to a "draft state" and produces a brand new
      // immutable state based off those changes
      state.users = action.payload
    },
    setLoading: (state, action) => {
      state.loading = action.payload
    },
    setSuccess: (state, action) => {
      state.success = action.payload.status
      state.message = action.payload.message
    },
    setError: (state, action) => {
      state.error = action.payload.status
      state.message = action.payload.message
    }
  }
})

export const { setUsers, setLoading, setSuccess, setError, setMessage } = usersSlice.actions;

// The function below is called a selector and allows us to select a value from
// the state. Selectors can also be defined inline where they're used instead of
// in the slice file. For example: `useSelector((state: RootState) => state.counter.value)`
export const selectUsers = (state) => state.users.users
export const selectLoading = (state) => state.users.loading
export const selectSuccess = (state) => state.users.success
export const selectError = (state) => state.users.error
export const selectMessage = (state) => state.users.message

export default usersSlice.reducer;

乙。店铺

  • store.js
import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit'
import usersReducer from '../slices/users'

export const store = configureStore({
  reducer: {
    users: usersReducer
  },
  middleware: getDefaultMiddleware({
    serializableCheck: false
  })
})
C。应用组件
import { Provider } from 'react-redux'
import { store } from '../app/store'

export default function App() {
  return {
    <>
      <Provider store={store}>
        {/* your content... */}    
      </Provider>
    </>
  }
}
D.组件(你使用 redux 的地方)
import { useContext, useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { selectUsers, selectLoading, selectSuccess, selectError, selectMessage, setUsers, setLoading, setSuccess, setError } from '../slices/users'
import axios from 'axios'

export default function HomePage() {
  const dispatch = useDispatch()
  const users = useSelector(selectUser)
  const loading = useSelector(selectLoading)  
  const success = useSelector(selectSuccess)
  const error = useSelector(selectorError)
  const message = useSelector(selectorMessage)

  useEffect(() => {
    async function init() {
      dispatch(setLoading(true))
      const response = await axios.get('http://localhost:5000/users')
      
      if(response?.status == 200) {
        dispatch(setUsers(response?.data?.data))
        dispatch(setSuccess({ status: true, message: 'Successfully get users data.' }))
      } else {
        dispatch(setError({ status: true, message: 'Failed to get data.' }))
      }

      dispatch(setLoading(false))
    }
    return init()
  }, [])

  return {
    <>
      {user}
    </>
  }
}