如何在 Redux api 调用期间在组件上设置加载布尔值

How to set a loading boolean on component during Redux api call

我正在创建一个基于 React, Redux and Redux-Thunk 的项目。

在下面的示例中,我列出了每个 "project" 并允许用户 "Increment"(对 API 进行了 1 秒的虚假调用)并更新了 MainApp 组件的状态(以显示加载中)

问题: 如何在 incrementProject 操作完成后直接进入 MainApp 组件?

我搜索了很多关于它的内容,但没有找到任何东西。处理这种情况最好的方法是什么?

想法:


我没有包含所有 actions/reducers/api 调用,因为它是非常基本的代码。

MainApp 组件

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect, Provider } from 'react-redux';

import { requestProjects, incrementProject } from '../actions';

class MainApp extends Component {

  constructor(props) {
    super(props);
    this.state = { loadingProjectsIds: [] };
  }
  componentDidMount() {
    const { requestProjects } = this.props;
    requestProjects();
  }

  render() {

    const { projectStore, incrementProject } = this.props;
    const { loadingProjectsIds } = this.state;

    const incrementProject = (project) => {
      let ids = this.state.loadingProjectsIds;
      ids.push(project._id);
      this.setState({
        loadingProjectsIds: ids
      });

      incrementProject(project._id);
    }

    return (
      <ul>
          {projectStore.projects.map(project => (
            <li key={`project-${project.key}`}>
              {project.name} 
              {
                loadingProjectsIds.indexOf(project._id) !== -1) 
                ? Incrementing...
                : <a>Increment</a>
              }
            </li>
          ))}
      </ul>
    );
  }
};

export default connect((state) => { project } = state), (dispatch) => ({
  requestProjects: () => dispatch(requestProjects()),
  incrementProject: (_id) => dispatch(incrementProject(_id)),
})(MainApp);

增量动作

export function incrementProject(projectId) {
  return async dispatch => {
    dispatch({type: 'PROJECT_INC', projectId});

    let { err, payload } = await API.incProject({projectId});

    if (err) {
      dispatch({type: 'PROJECT_INC_ERR', err});
    }
    else {
      dispatch({type: 'PROJECT_INC_SUCCESS', payload});
    }
  };
};

没有最佳解决方案。如果给定的 action 被调度,一切都取决于谁感兴趣。一个更通用的方法(我们使用的)是在你的减速器中有一个 TOGGLE_LOADING 动作和一个 loading 属性。像这样

const initialState = {
    value : '',
    loading: false,
    error: false
}

export const reducer = (state = initialState, action) =>{
    switch(action.type){
        case 'TOGGLE_LOADING' : return{
            ...state,
            loading : !state.loading
        }

        case 'STORE_VALUE' : return{
            ...state,
            loading: false
        }

        case 'ERROR_FETCHING' : return{
            ...state,
            loading : false,
            error: true,
        }

        default : return state
    }
}

在你的action creator

里面
const fetchValue = () =>{
    return dispatch =>{
        dispatch({type: 'TOGGLE_LOAD'})
        apiCall()
            .then(value =>{
                dispatch({type: 'STORE_VALUE'})
            })
            .catch(error =>{
                dispatch({type: 'FETCH_ERROR'})
            })
    }
}

现在您的 state 中配置了 loading 属性。只需在您的组件中使用它

   class Component extends React.Component{
    componentDidMount(){
        fetchValue()
    }

    render(){
        const { loading } = this.props
        return loading ? 'Loading' : <Content />
    }
}