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

How to perform async axios call to REST api and update the store (redux thunk is confusing)?

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

这是一个工作示例,它 return 是普通的 json 对象

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

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

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)
})

你理解错了。网络请求应在操作文件而不是缩减程序中执行。

Reducers 是你想要从 redux-store 更新状态的位置,基于你从 redux-action 获得的 API 结果。这就是为什么大多数时候你会在几乎所有的减速器中看到 switch 语句的原因,原因是你的 actions 可以分派任何 type 而你需要一个 switch 语句根据特定类型更新商店

好的,让我们分解一下。

I have read about redux thunk, but I am still a bit confused with that so I was trying to make an asynchronous request inside of reducer.

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

Redux Thunk middleware allows you to write action creators that return a function instead of an action. The thunk can be used to delay the dispatch of an action, or to dispatch only if a certain condition is met. The inner function receives the store methods dispatch and getState as parameters.

An action creator that returns a function to perform asynchronous dispatch:

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);
  };
}

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