简体   繁体   English

在 react-redux 中异步操作后更新状态

[英]Updating state after async action in react-redux

The general idea is that someone clicks the button, action fetches data from server and dispatches it.一般的想法是有人点击按钮,动作从服务器获取数据并调度它。 The state is updating and the content on the page is changing.状态在更新,页面上的内容也在变化。 The action looks exacly like that:动作看起来就像这样:

     export function getPosts(page){
     return function(dispatch){
      axios.get(`${ROOT_URL}/home?page=${page}`)
          .then(response => {
            dispatch ({
            type: FETCH_POSTS,
            payload: response.data        
          })
          })
          .catch((error) => {
            console.log(error)
          });
    }
    }

Reducer is pretty straightforward: Reducer 非常简单:

      export default function(state={}, action){
      switch(action.type){
        case FETCH_POSTS:
        return {posts: action.payload, ...state};
      }
      return state;
    }

And the main page is looking just like that:主页看起来就像这样:

    import React, { Component } from 'react';
    import * as actions from '../actions';
    import RequireAuth from './auth/require_auth';
    import { connect } from 'react-redux';
    import { compose } from 'redux';
    class Home extends Component {

    constructor(props) {
      super(props);
      this.state = {
        posts: 'loading....',
      };
      this.props.getPosts();
    }  
    handlePage(){
    console.log(this.props);
    let page = 3;
    this.props.getPosts();
    }

    componentWillReceiveProps(nextProps){
      let posts = nextProps.posts.posts.map((post) => {
      return (<li key={post._id}>{post.date}</li>)
      });
      this.setState({posts: posts});

    }
    shouldComponentUpdate(nextState, nextProps){
    console.log(nextProps.posts, nextState.posts);
    return true;
    }
      render(){
        return(
          <div>
            {this.state.posts}
            <button onClick={this.handlePage.bind(this)}>change something</button>
          </div>
          )
    }
    }

    function mapStateToProps(state){
      return {posts: state.post}
    }

    export default connect(mapStateToProps, actions)(Home);

I was thinking that the state will update in componentWillReciveProps but that is not happening.我以为状态会在 componentWillReciveProps 中更新,但这并没有发生。 The data will be fetched after some time so i can't set state just like that.数据将在一段时间后获取,因此我无法像那样设置状态。 Any idea how to do this ?知道如何做到这一点吗?

for async actions, there are two possible ways:对于异步操作,有两种可能的方式:

  1. an additional status flag附加status标志
  2. additional actions额外的行动

The workflow would like:工作流程如下:

  1. Fetching data, dispatch an action, which sets status to 'fetching'获取数据,调度一个动作,将status设置为'fetching'
  2. if fetching is successfull, dispatch an action, which sets status to 'success'如果获取成功,则调度一个动作,将status设置为'success'
  3. if fecthing fails, dispatch an action, which sets status to 'error'如果 fecting 失败,则调度一个动作,将status设置为'error'

Further reading: Redux :: Async actions进一步阅读: Redux :: 异步操作

Edit: redux-saga is more appropriate than redux-thunk as it is a container for doing all your side effects. 编辑: redux-saga比redux-thunk更合适,因为它是一个用于完成所有副作用的容器。

You're performing an async action, so your dispatcher is 'dispatching' the action before the response of your request is received, that's why your store is not updating and hence your state too. 您正在执行异步操作,因此您的调度员会在收到您的请求响应之前“调度”该操作,这就是您的商店未更新的原因,也是您的状态。

To do this successfully you have to provide some timeout to make sure the response is received before dispatching the action. 要成功完成此操作,您必须提供一些超时以确保在分派操作之前收到响应。 Something like this: 像这样的东西:

 export function yourFunction(param) {
      return dispatch => {
        callApi(api_url, 'GET').then(res => {
           setTimeout(() => {
            dispatch(yourActionObject);
          }, 1000)
        }).catch(error => { console.log(error) })
      }
    }

But that timeout (1000 ms) may or may not work. 但是超时(1000毫秒)可能有效,也可能无效。 Instead you can use a middleware like redux-thunk . 相反,你可以使用像redux-thunk这样的中间件。 It will take care of your timeout delay. 它会照顾你的超时延迟。

Redux Thunk middleware allows you to write action creators that return a function instead of an action. Redux Thunk中间件允许您编写返回函数而不是动作的动作创建者。 The thunk can be used to delay the dispatch of an action, or to dispatch only if a certain condition is met. thunk可用于延迟动作的发送,或仅在满足某个条件时发送。

To use redux-thunk: 要使用redux-thunk:

Installation 安装

npm install --save redux-thunk

Then, to enable Redux Thunk, use applyMiddleware(): 然后,要启用Redux Thunk,请使用applyMiddleware():

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

const store = createStore(
  rootReducer,
  applyMiddleware(thunk)
);

Then you can normally use your dispatch function without wrapping it in setTimeout. 然后你通常可以使用你的调度函数而不将它包装在setTimeout中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM