使用异步获取对 redux 做出react

IT技术 reactjs asynchronous redux wait
2021-05-12 07:34:33

我正在使用 react redux,并尝试调用 rest-api,并返回数据。提取是异步的,我只需要在提取完成时返回值。

我尝试了以下操作,但这不能正常工作(带星号的行上没有“等待”) - 我该怎么办?

代码:

-----

var _getData = function()  
{
return new Promise((resolve, reject) => {
    let options = {
        method: 'GET',
    }
    let _url = "my web return json";
    fetch(_url, options)
    .then(response => 
        response.json().
            then(data => resolve({
                data: data,
                status: response.status
            }))
            .catch(err => reject(
                {error_data: err}
                )
            )

    )
    .catch(
        err =>
        {
            console.log(err);
            reject(err);
        }
    )
    })
}

// ...
const reducer = (state = initialState, action) => {
if (action.type === 'GET_DATA_FIRST') {
    let x = {}
    setTimeout(function () {
        _getData().then(
            (res) =>
            {
                x = res;
            }
        ) }, 0)
    // ******** NEED TO WAIT UTIL _getData ends and return a value ***** 


    return {
        ...state,
        myData: x
    }
}
return state;
};

谢谢。

1个回答

在非常基础的层面上,您需要将异步操作从减速器中移出。相反,您应该fetch()在您的动作创建者中触发 并fetch()完成并解析您的 JSON 响应后分派一个动作它看起来像下面这样。这个例子使用redux-thunk作为异步中间件。添加了一个额外的动作来表示何时fetch()开始调用以及何时接收和解析数据。这可用于显示加载消息或可能禁用和/或有条件地呈现特定内容。

我创建了一个工作示例

店铺:

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers';

const middleware = [ thunk ];

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

export default store;

减速器:

import { combineReducers } from 'redux';
import { GET_DATA_FIRST, REQUEST_DATA } from '../actions';

const initialState = {
  isFetching: false,
  myData: []
};

const things = (state = initialState, action) => {
  switch (action.type) {
    case REQUEST_DATA:
      return {
        ...state,
        isFetching: true
      };
    case GET_DATA_FIRST:
      return {
        ...state,
        isFetching: false,
        myData: action.myData
      };
    default:
      return state;
  }
};

const rootReducer = combineReducers({
  things // this key can be called anything, 'things' is just an example
});

export default rootReducer;

行动:

export const REQUEST_DATA = 'REQUEST_DATA'; // action to represent waiting for response
export const GET_DATA_FIRST = 'GET_DATA_FIRST'; // action to represent receiving of data

export const requestData = () => ({ type: REQUEST_DATA });

export const getDataFirst = myData => ({ type: GET_DATA_FIRST, myData });

export const fetchData = () => dispatch => {
  dispatch(requestData());
  return getData().then(things => {
    // simulated delay
    setTimeout(() => {
      return dispatch(getDataFirst(things))
    }, 1000);
  });
};

const getData = () => {  
  return fetch('https://jsonplaceholder.typicode.com/todos').then(res => res.json());
}

零件:

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { fetchData } from './actions';

class ThingsList extends Component {
  constructor(props) {
    super(props);    
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.props.dispatch(fetchData());
  }

  render() {
    return (
      <div>
        <button type="button" onClick={this.handleClick}>GET DATA</button>
        {this.props.isFetching && <div>Loading...</div>}
        <ul>
          {this.props.myData.map(d => <li key={d.id}>{d.title}</li>)}
        </ul>        
      </div>
    );
  }
}

const mapStateToProps = ({ things: { myData, isFetching } }) => ({
  myData,
  isFetching
});

export default connect(mapStateToProps)(ThingsList);

注意诸如fetchData()传递dispatch到内部动作之类的动作是如何起作用的。这用于将动作/有效负载分派给减速器。reducer 应该只需要准备好使用的数据来更新状态。

希望这有帮助!