如何在React Redux Saga App中延迟(例如1s)显示加载指示符?

时间:2017-07-31 22:55:19

标签: javascript reactjs redux react-redux redux-saga

我正在使用reducer检查各种动作状态,如成功,待定,错误等。我希望在延迟1秒后显示加载指示。如果响应在1s之前,那么我不想显示加载指示器。

目前,我没有更新挂起状态的加载状态,而是使用setTimeout从render函数触发一个动作。

在超时期限之前传递响应时会产生问题。我该如何解决这个问题?

reducer.js:

const initialState = {
  error: false,
  loading: false,
  showModal: false,
};

export default function appReducer(state=initialState, action) {

  if (action.type.endsWith('ERROR'))
    return {
      ...state,
      error: true,
      loading: false,
      showModal: true,
    };
  else if (action.type.endsWith('PENDING'))
    return {
      ...state,
      error: false,
      loading: false,
    };
  else if (action.type.endsWith('SUCCESS'))
      return {
        ...state,
        error: false,
        loading: false,
      };
  else if (action.type === errorModalActionTypes.CLOSE_MODAL.ACTION)
    return {
      ...state,
      showModal: false,
    };
  else if (action.type === loadingIndicatorActionTypes.UPDATE_LOADING.ACTION)
    return {
      ...state,
      loading: true,
    };
  else
    return state;
}

saga.js

export function* getCollections(action) {
  try {
    yield put({ type: GET_COLLECTIONS.PENDING });
    const collections = yield call(getCollectionsAPI);
    yield put({ type: GET_COLLECTIONS.SUCCESS, collections });
  } catch (error) {
    yield put({ type: GET_COLLECTIONS.ERROR, error });
  }
}

// These are the watchers that trigger the start of a saga

export default function* saga() {
  yield fork(takeEvery, GET_COLLECTIONS.ACTION, getCollections);
}

LoadingIndicator.js

import React, { Component } from 'react';
import { connect } from 'react-redux';

import { isLoading, hasError } from './selectors';
import { updateLoading } from './actions';
import LoadingIndicatorComponent  from '../../../../components/loadingIndicator';
import './loadingIndicator.css';

export class LoadingIndicator extends Component {

  render() {
    console.log('called');
    const { loading, error } = this.props;

    if (!error)
      setTimeout(this.props.updateLoading, 1000);

    return (
      <div className={`${loading && !error ? 'show' : 'hidden'}`}>
        <LoadingIndicatorComponent>
          Loading...
        </LoadingIndicatorComponent>
      </div>
    );
  }

}

const mapStateToProps = (state) => ({
  loading: isLoading(state),
  error: hasError(state),
});

export default connect(mapStateToProps, { updateLoading })(LoadingIndicator);

1 个答案:

答案 0 :(得分:1)

鉴于您的架构,我建议的是:

+---------------------------+-----------------------------------------+-------------------------------------------+-------------------------------------------+---------------------------------------------+----------------------------------------------+------------------------------------------------+
|            sku            | embroidery_imprint_id_setup_sku_price_1 | embroidery_imprint_id_running_sku_price_1 | screen_print_imprint_id_setup_sku_price_1 | screen_print_imprint_id_running_sku_price_1 | laser_engraving_imprint_id_setup_sku_price_1 | laser_engraving_imprint_id_running_sku_price_1 |
+---------------------------+-----------------------------------------+-------------------------------------------+-------------------------------------------+---------------------------------------------+----------------------------------------------+------------------------------------------------+
| IP-205-1067-16            | NULL                                    | NULL                                      |                                        55 | 0.99                                        |                                           45 | 0.59                                           |
| IP-205-1067-16-39423495   | NULL                                    | NULL                                      |                                        55 | 0.99                                        |                                           45 | 0.59                                           |
| IP-205-1067-16-1272347    | NULL                                    | NULL                                      |                                        55 | 0.99                                        |                                           45 | 0.59                                           |
| IP-205-1067-16-56185      | NULL                                    | NULL                                      |                                        55 | 0.99                                        |                                           45 | 0.59                                           |
| IP-205-1067-16-1706399150 | NULL                                    | NULL                                      |                                        55 | 0.99                                        |                                           45 | 0.59                                           |
+---------------------------+-----------------------------------------+-------------------------------------------+-------------------------------------------+---------------------------------------------+----------------------------------------------+------------------------------------------------+

这里有几点需要注意:

  1. 如果没有别的,请从export class LoadingIndicator extends Component { constructor(props) { super(props); this.timeoutID = null; this.state = { showIndicator: false, }; } componentDidMount() { this.ensureTimer(this.props); } componentWillUnmount() { this.destroyTimer(); } componentWillReceiveProps(props) { if (props.loading !== this.props.loading || props.error !== this.props.error) { this.ensureTimer(props); } } ensureTimer(props) { if (props.loading && !props.error) { if (!this.timeoutID) { this.timeoutID = setTimeout(() => { this.timeoutID = null; this.setState({showIndicator: true }); }, 1000); } } else { this.destroyTimer(); } } destroyTimer() { clearTimeout(this.timeoutID); this.timeoutID = null; this.setState({showIndicator: false }); } render() { const { loading, error } = this.props; return ( <div className={`${this.state.showIndicator ? 'show' : 'hidden'}`}> <LoadingIndicatorComponent> Loading... </LoadingIndicatorComponent> </div> ); } } const mapStateToProps = (state) => ({ loading: isLoading(state), error: hasError(state), }); export default connect(mapStateToProps, { updateLoading })(LoadingIndicator); 应该是纯函数的答案中得到答案。它不应该改变任何状态。相反,给予相同的道具和状态,它应该每次返回相同的东西(并且没有设置副作用)
  2. 相反,我做的选择是通过showIndicator使用state。还有另一个世界,你将逻辑包装在父容器中,但这是获取示例的最简单方法。
  3. 这背后的主要逻辑如下:当组件第一次安装时,或者当道具改变时,看看是否应该显示加载对话框。这是通过setTimeout完成的,然后只更新showIndicator标志。如果条件不再成立,则销毁计时器,并将showIndicator设置为false。
  4. 我会阅读其他反应生命周期钩子,以确保你需要听取所有这些不同事件的原因:https://facebook.github.io/react/docs/react-component.html