首页 > 解决方案 > 在反应中获取未定义的错误值

问题描述

我想在我的应用程序中使用错误值作为警报。我的服务器响应也给了我正确的响应。但是在反应中使用时错误值显示未定义。

<b>Response Getting from API request</b>


{"success":false,"error":"Product Not Found"}

<b>code in react file</b>

    const alert = useAlert();
      const dispatch = useDispatch();
      
      const { loading, error, products } = useSelector((state) => state.products);
      useEffect(() => {
        if (error) {
          alert.error(error);
        
        }
    
        dispatch(getProduct());
      }, [dispatch, error, alert]);


    <b>Reducer</b>
    export const productReducer = (state = { products: [] }, action) => {
      switch (action.type) {
        case ALL_PRODUCT_REQUEST:
          return {
            loading: true,
            products: [],
          };
        case ALL_PRODUCT_SUCCESS:
          return {
            loading: false,
            products: action.payload.products,
            productsCount: action.payload.productsCount,
          };
        case ALL_PRODUCT_FAIL:
          return {
            loading: false,
            error: action.payload,
          };
    
        case CLEAR_ERRORS:
          return {
            ...state,
            error: null,
          };
    
        default:
          return state;
      }
    };

    <b>action</b>

    export const getProduct = () => async (dispatch) => {
      try {
        dispatch({ type: ALL_PRODUCT_REQUEST });
        const { data } = await axios.get("/api/v1/products");
    
        dispatch({
          type: ALL_PRODUCT_SUCCESS,
          payload: data,
        });
      } catch (error) {
        dispatch({
          type: ALL_PRODUCT_FAIL,
          payload: error.response.data.message,
        });
      }
    };

<b>store file</b>

import { createStore, combineReducers, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import { composeWithDevTools } from "redux-devtools-extension";
import {
  productReducer,
  productDetailsReducer,
} from "./reducers/productReducer";

const reducer = combineReducers({
  products: productReducer,
  productDetails: productDetailsReducer,
});

let initialState = {};
const middleware = [thunk];

const store = createStore(
  reducer,
  initialState,
  composeWithDevTools(applyMiddleware(...middleware))
);

export default store;

无法看到此功能工作警报。错误(错误)。当我控制台此错误时,它显示未定义。我想在出现错误时显示“未找到产品”警报。

标签: reactjsreact-reduxmern

解决方案


这是因为useSelector实际上是从state前端(由 Redux 管理)访问数据。这是从 API 获取后的数据,所以这纯粹是data来自 API 的部分,而不是errorloading

products在这里,当您尝试访问state. 它不会有类似的字段,loading或者error只有一个对象数组product

为了解决这个问题,你应该在你的 Redux 状态中以结构化的方式存储errorloading响应来自 API 的响应,然后你才能在每个访问此状态的 React 组件中访问它们。

例如代码:

const { loading, error, products } = useSelector((state) => {
// Curly braces with return should not be on next line
return { 
   loading: state.loading,
   products: state.products,
   error:state.error
});

另外,我建议使用react-query之类的包来很好地解决此类用例

选择

编写自己的钩子来处理此类异步任务

挂钩代码

import { useCallback, useEffect, useState } from "react"

export default function useAsync(callback, dependencies = []) {
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState()
  const [value, setValue] = useState()

  // Simply manage 3 different states and update them as per the results of a Promise's resolution
  // Here, we define a callback
  const callbackMemoized = useCallback(() => {
    setLoading(true)
    setError(undefined)
    setValue(undefined)
    callback()
      // ON SUCCESS -> Set the data from promise as "value"  
      .then(setValue)
      // ON FAILURE -> Set the err from promise as "error"  
      .catch(setError)
      // Irresp of fail or success, loading must stop after promise has ran
      .finally(() => setLoading(false))
      // This function runs everytime some dependency changes
  }, dependencies)

  // To run the callback function each time it itself changes i.e. when its dependencies change
  useEffect(() => {
    callbackMemoized()
  }, [callbackMemoized])

  return { loading, error, value }
}

在组件中使用这个钩子

import useAsync from "./useAsync"

export default function AsyncComponent() {
  const { loading, error, value } = useAsync(() => {
    // 3 states and their updated versions are returned while the promise is getting resolved
    return new Promise((resolve, reject) => {
      const success = false
      setTimeout(() => {
        success ? resolve("Hi") : reject("Error")
      }, 1000)
    })
  })

  return (
    <div>
      <div>Loading: {loading.toString()}</div>
      <div>{error}</div>
      <div>{value}</div>
    </div>
  )
}

推荐阅读