如何对 REST api 执行异步 axios 调用并更新存储(redux thunk 令人困惑)?

Posted

技术标签:

【中文标题】如何对 REST api 执行异步 axios 调用并更新存储(redux thunk 令人困惑)?【英文标题】:How to perform async axios call to REST api and update the store (redux thunk is confusing)? 【发布时间】:2019-12-29 23:07:54 【问题描述】:

所以,我必须向 REST api 发出异步请求,我已经阅读了有关 redux thunk 的信息,但我仍然对此有点困惑,所以我试图在 reducer 中发出异步请求

这是一个工作示例,它返回纯 json 对象

 return Object.assign(, state,
  texts: state.texts.concat( data: 'some text') )

但是当涉及到网络请求时,它没有给出任何错误,只是看起来返回不起作用,所以这就是我的组件无法更新的原因

axios.get('https://dog.ceo/api/breeds/image/random').then(res => 
    return Object.assign(, state,
  texts: state.texts.concat( data: action.payload ) )
)

即使 setTimeout() 也不起作用...

setTimeout(()=> 
    return Object.assign(, state,
 texts: state.texts.concat( data: 'some text' ) )
,100)

按照某些人的要求完成代码... 减速机:

import axios from 'axios'

const LOAD = 'LOAD'

let initialState = 
   texts: [
       data: 'Orinary text' 
   ]


export let textReducer = (state = initialState, action) => 
   switch (action.type) 
      case LOAD:
         axios.get('https://dog.ceo/api/breeds/image/random').then(res => 
            return Object.assign(, state,
                texts: state.texts.concat( data: action.payload ) )
         )
      default:
         return state
   


export let loadActionCreator = () => 
   return  type: LOAD, payload: 'res.data.message ' 

商店:

import  createStore, combineReducers  from "redux";
import  textReducer  from './text-reducer'

let reducers = combineReducers(
   textReducer: textReducer
)

export let store = createStore(reducers)

组件:

import  loadActionCreator  from './Redux/text-reducer'
import  connect  from 'react-redux'

function mapStateToProps(state) 
  return (
      state: state
  )


function mapDispatchToProps(dispatch) 
  return (
      loadActionCreator: () => dispatch(loadActionCreator())
  )


function App(props) 
  return (
    <>
      props.state.textReducer.texts.map(el => 
        return (
          <div>el.data</div>
        )
      )
      <button onClick=() => props.loadActionCreator()>Add data</button>
    </>
  );


export default connect(mapStateToProps, mapDispatchToProps)(App)

index.js

import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import  subscribe  from 'redux'
import  store  from './Redux/store'
import  Provider  from 'react-redux'

let rerender = (store) => 
   ReactDOM.render(
      <Provider store=store>
         <App />
      </Provider>,
      document.getElementById('root'))


rerender(store)

store.subscribe(() => 
   rerender(store)
)

【问题讨论】:

您能否展示一个完整的示例,以便我们了解您想要做什么的更多背景信息? @Webber:完成,我只添加了 redux 部分 @Lucifer:您还应该共享action 文件和component 文件。典型流程是从componentactionreducer 再回到component @Isaac:我都发过了 【参考方案1】:

好的,让我们分解一下。

我已经阅读了有关 redux thunk 的信息,但我仍然对此感到有些困惑,因此我试图在 reducer 中发出异步请求。

Redux Thunk 为您想要做的事情提供了他们的库。所以你在正确的方向。在下方查看他们的movitation。

Redux Thunk 中间件允许您编写返回函数而不是动作的动作创建器。 thunk 可用于延迟动作的分派,或仅在满足特定条件时分派。内部函数接收 store 方法 dispatch 和 getState 作为参数。

返回一个函数来执行异步调度的动作创建者:

const INCREMENT_COUNTER = 'INCREMENT_COUNTER';

function increment() 
  return 
    type: INCREMENT_COUNTER
  ;


function incrementAsync() 
  return dispatch => 
    setTimeout(() => 
      // Yay! Can invoke sync or async actions with `dispatch`
      dispatch(increment());
    , 1000);
  ;

但是,您正在尝试执行异步调用,而没有任何异步中间件。这很难(正确地)执行,除非您从组件执行调用,在 thunk 中或使用其他设计模式(如 sagas)。

让我们继续使用 Redux Thunk,看看您的实现会是什么样子。我创建了一个working example,坚持最基本的。

相关部分是您只有动作创建者,但没有 thunk:

// Action creators
export const textLoaded = text => 
  return 
    type: LOADED,
    text
  ;
;

// Thunks
export function textLoadRequest() 
  return dispatch => 
    /**
     * If you want to use axios, to recieve data; replace the
     * `setTimeout` with `axios.get()` and perform the dispatch
     * in the `then()` callback.
     */
    setTimeout(() => 
      dispatch(textLoaded("text after timeout"));
    , 1000);
  ;

请不要犹豫,就此答案的有用性提供反馈。

【讨论】:

【参考方案2】:

你理解错了。网络请求应该在操作文件而不是减速器上执行。

Reducer 是您希望根据您从 redux-action 获得的 API 结果从 redux-store 更新状态的位置。这就是为什么大多数时候你会在几乎所有的 reducer 中看到 switch 语句的原因,原因是你的 actions 可以调度任何 type 并且你需要一个 switch 语句来根据特定类型更新存储

【讨论】:

操作也无济于事,因为它需要返回对象 错误:操作必须是普通对象。使用自定义中间件进行异步操作。 'axios.get('dog.ceo/api/breeds/image/random').then(res => return type: LOAD, payload: res.data.message )' 默认 action 期望返回以类型为键的普通对象。这就是为什么你需要redux-thunk 的帮助,它允许你dispatch,而不是返回单个对象 @Lucifer: 如github.com/reduxjs/redux-thunk 所示,您可以在action creator 中使用dispatch 语句代替return

以上是关于如何对 REST api 执行异步 axios 调用并更新存储(redux thunk 令人困惑)?的主要内容,如果未能解决你的问题,请参考以下文章

如何对使用 Axios(或其他异步更新)的 Vue 组件进行单元测试?

如何允许快速后端 REST API 在使用 axios 的反应前端中设置 cookie?

如何在 Vuex 的操作中使用 axios 获取 Rest API 数据?

用 PHP Rest API 反应 axios,如何编写 baseurl [重复]

我应该让我的 REST 客户端 API 库异步(Java 8)

在 Vue 中用 Axios 异步请求API