Redux 工具包和 Axios

Posted

技术标签:

【中文标题】Redux 工具包和 Axios【英文标题】:Redux Toolkit and Axios 【发布时间】:2020-05-29 21:50:29 【问题描述】:

我正在使用 Redux Toolkit 通过 Axios 连接到 API。 我正在使用以下代码:

const products = createSlice(
    name: "products",
    initialState: 
        products[]
    ,
    reducers: 
        reducer2: state => 
            axios
                .get('myurl')
                .then(response => 
                    //console.log(response.data.products);
                    state.products.concat(response.data.products);
            )

        
    
);

axios 正在连接到 API,因为要打印到控制台的注释行正在向我显示数据。但是, state.products.concat(response.data.products);抛出以下错误:

TypeError:无法在已撤销的代理上执行“获取”

有没有办法解决这个问题?

【问题讨论】:

【参考方案1】:

我更愿意将createAsyncThunk 用于API 数据和extraReducers

假设这个页面名称是productSlice.js

import createSlice,createSelector,PayloadAction,createAsyncThunk, from "@reduxjs/toolkit";

export const fetchProducts = createAsyncThunk(
  "products/fetchProducts", async (_, thunkAPI) => 
     try 
        //const response = await fetch(`url`); //where you want to fetch data
        //Your Axios code part.
        const response = await axios.get(`url`);//where you want to fetch data
        return await response.json();
       catch (error) 
         return thunkAPI.rejectWithValue( error: error.message );
      
);

const productsSlice = createSlice(
   name: "products",
   initialState: 
      products: [],
      loading: "idle",
      error: "",
   ,
   reducers: ,
   extraReducers: (builder) => 
      builder.addCase(fetchProducts.pending, (state) => 
        state. products = [];
          state.loading = "loading";
      );
      builder.addCase(
         fetchProducts.fulfilled, (state,  payload ) => 
            state. products = payload;
            state.loading = "loaded";
      );
      builder.addCase(
        fetchProducts.rejected,(state, action) => 
            state.loading = "error";
            state.error = action.error.message;
      );
   
);


export const selectProducts = createSelector(
  (state) => (
     products: state.products,
     loading: state.products.loading,
  ), (state) =>  state
);
export default productsSlice;

在您的store.js 中添加productsSlice: productsSlice.reducer 到店外减速器。

然后在组件中使用添加这些代码......我也更喜欢使用钩子

import  useSelector, useDispatch  from "react-redux";

import 
  fetchProducts,
  selectProducts,
 from "path/productSlice.js";

然后最后一部分像这样在你的主管内部调用这些方法

const dispatch = useDispatch();
const  products  = useSelector(selectProducts);
React.useEffect(() => 
   dispatch(fetchProducts());
, [dispatch]); 

最后,您可以在组件中以products 的身份访问数据。

【讨论】:

我对这个答案表示赞赏,并强烈建议任何使用 react-redux 的人完整阅读这个“redux essentials”文档,并非常虔诚地遵循这些模式,它们太棒了! redux.js.org/tutorials/essentials/part-5-async-logic 这个答案非常详细。我没见过比这更好的了。这非常重要,尤其是 createAsyncThunk。谢谢【参考方案2】:

这是因为你的 reducer 函数不是纯函数,它不应该有任何异步调用。

这样的东西应该可以工作。它将解决您遇到的错误

const products = createSlice(
    name: "products",
    initialState: 
        products: []
    ,
    reducers: 
        reducer2: (state,  payload ) => 
                return  products: [...state.products, ...payload]
         )

      
    
);

而且api应该在外面调用

const fetchProducts = () => 

   axios.get('myurl')
     .then(response => 
        //console.log(response.data.products);
        store.dispatch(products.actions.reducer2(response.data.products))
   )
;

PS:上面的代码没试过运行,可能需要根据需要进行修改。

【讨论】:

FWIK,return products: [...state.products, ...payload] 可以缩写为 state.products.push(payload) 甚至(不确定)state.products = payload。这是 Redux Toolkit 的魔力的一部分 ;)

以上是关于Redux 工具包和 Axios的主要内容,如果未能解决你的问题,请参考以下文章

如何将 axios 添加到 react-redux-universal-hot-example 入门套件?

更换 redux 工具包商店或其他方式拥有两个商店

mirror.js 整合redux的好工具

使用 axios 和 redux-thunk 以 redux-form 发布请求

使用 axios 和 redux 的正确方法

redux 工具包查询和创建异步 thunk 有啥区别?