javascript - 如何延迟(例如 1 秒)React Redux Saga App 中加载指示器的显示?

标签 javascript reactjs redux react-redux redux-saga

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

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

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

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

传奇.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);

最佳答案

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

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

这里有几点需要注意:

  1. 如果不出意外,请不要回答 render() 应该是纯函数的问题。它不应该改变任何状态。相反,给定相同的 Prop 和状态,它应该每次都返回相同的东西(并且没有设置副作用)
  2. 相反,我做出的选择是通过 showIndicator 使用状态。在另一个世界中,您可以将逻辑包装在父容器中,但这是让示例得到理解的最简单方法。
  3. 这背后的主要逻辑如下:当组件第一次挂载时,或者每当 props 发生变化时,看看是否应该显示加载对话框。这是通过 setTimeout 完成的,然后只更新 showIndicator 标志。如果条件不再成立,则计时器被销毁,showIndicator 设置为 false。
  4. 我会阅读其他 React 生命周期钩子(Hook),以确保您需要监听所有这些不同事件的原因是有意义的:https://facebook.github.io/react/docs/react-component.html

关于javascript - 如何延迟(例如 1 秒)React Redux Saga App 中加载指示器的显示?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45426499/

相关文章:

javascript - 渲染谷歌折线图,曲线类型未设置且动画未按预期工作

css - 为新的 Web 组件更新 UI Framework CSS

reactjs - 为 Web (HTML/JavaScript) 导出 React Native 应用程序?

javascript - "TypeError: Cannot destructure property ' 产品 ' of ' 产品详细信息 ' as it is undefined"

javascript - 还原, react 。如何将 mapStateToProps 添加到 this.state 中?

javascript - 使用 JQuery 提示保存按钮防止多次提交

javascript - 使用node.js和socket.io在Heroku上发布应用程序

javascript - 错误 : "Uncaught TypeError: Cannot read property ' length' of null"Chart. js

javascript - 如何使用 material-ui 图标中的图标?

javascript - 即使状态发生变化而没有突变,React-Redux connect() 也不会更新组件