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