【问题标题】:Actions are getting called infinitely when making API calls in redux-react在 redux-react 中进行 API 调用时,动作被无限调用
【发布时间】:2020-07-31 16:18:18
【问题描述】:

我试图显示加载,直到 RootContainer 内的所有组件完成它们的 api 调用,但我的应用程序正在调用调度操作的无限循环中运行,并且应用程序始终保持加载状态。它在 30 秒内拨打了大约 1300 个电话。这是我的代码。我无法找到应用程序在无限循环中运行的原因。

App.js

import React, { Component } from 'react';
import RootContainer from './components/RootContainer'
import {Provider} from 'react-redux'
import store from './redux/store';

class App extends Component {
  render() {
    return (
      <Provider store={store}>
        <div className="App">
          <RootContainer/>
        </div>
      </Provider>
    )

  }
}

export default App;

RootContainer.js

import React from 'react'
import {connect} from 'react-redux'
import {mapStateToProps , mapDispatchToprops} from './mapFunctions.js'
import UserContainer from './UserContainer'
import TodoContainer from './TodoContainer'

class RootContainer extends React.Component{
  render(){
    if(this.props.userData.count===0){
      return (
        <div>
          <UserContainer/>
          <TodoContainer/>
        </div>
      );
    }else{
      return(
        <h2> Loading... </h2>
      )
    }

  }
}

export default connect(mapStateToProps,mapDispatchToprops)(RootContainer)

UserContainer.js

import React from 'react'
import {connect} from 'react-redux'
import {mapStateToProps , mapDispatchToprops} from './mapFunctions.js'

class UserContainer extends React.Component{
    constructor(props){
      super(props)
      this.state={
        userList:[]
      }
    }
    componentDidMount() {
        this.props.fetchUsers('https://jsonplaceholder.typicode.com/users').then(data =>{
          this.setState({
            userList:data
          })
        })
    }

    render(){
        console.log("count = "+this.props.userData.count);
        return (
          <div>
            <h2>User List</h2>
            <ul>
                {this.state.userList.map(item => {
                  return <li>{item.name}</li>;
                })}
            </ul>
          </div>
        )
    }
}

export default connect(mapStateToProps,mapDispatchToprops)(UserContainer)

TodoContainer.js

import {connect} from 'react-redux'
import { fetchUsers } from '../redux'
import {mapStateToProps , mapDispatchToprops} from './mapFunctions.js'

class TodoContainer extends React.Component{
    constructor(props){
      super(props)
      this.state={
        todoList:[]
      }
    }
    componentDidMount() {
        this.props.fetchUsers('https://jsonplaceholder.typicode.com/todos').then(data =>{
          this.setState({
            todoList:data
          })
        })
    }

    render(){
        return (
          <div>
            <h2>ToDo List</h2>
            <ul>
                {this.state.todoList.map(item => {
                  return <li>{item.title}</li>;
                })}
            </ul>
          </div>
        )

    }
}

export default connect(mapStateToProps,mapDispatchToprops)(TodoContainer)

UserActions.js

import { INCREMENT_COUNT ,DECREMENT_COUNT} from "./userTypes"
import axios from 'axios'

export const incrementCount = () =>{
    return {
        type:INCREMENT_COUNT
    }
}

export const decrementCount = () =>{
    return {

        type:DECREMENT_COUNT
    }
}

export const fetchUsers = (url) =>{
    console.log("fetchUsers called" + url)
    return(dispatch) => {
        dispatch(incrementCount())
        return fetch(url)
               .then(response => {
                 dispatch(decrementCount());
                 return response.data
               })
               .catch(error => {
                const errorMsg = error.message
                console.log("error = "+errorMsg)
                dispatch(decrementCount());
              })
    }
}

UserReducer.js

import  {INCREMENT_COUNT ,DECREMENT_COUNT} from "./userTypes"

const initialState = {
    count:0,
}

const reducer = (state = initialState,action) => {
    switch(action.type){
        case INCREMENT_COUNT:
            console.log("reducer called =increment")
            return{
               count: state.count+1,
            }
        case DECREMENT_COUNT:
            return{
                count:Math.max(0,state.count-1),
            }
        default: return state
    }
}

export default reducer

ma​​pFunctions.js

import { fetchUsers } from '../redux'

export const mapStateToProps = state =>{
    return {
        userData: state.user
    }
}
export const mapDispatchToprops = dispatch =>{
    return {
        fetchUsers: (url) => dispatch(fetchUsers(url))
    }
}

rootReducer.js

import { combineReducers } from 'redux'
import userReducer from './user/userReducer'

const rootReducer = combineReducers ({
    user:userReducer
})

export default rootReducer

store.js

import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import { composeWithDevTools } from 'redux-devtools-extension'
import logger from 'redux-logger'
import rootReducer from './rootReducer'

const store = createStore(rootReducer,
    composeWithDevTools(applyMiddleware(thunk,logger))
)

export default store

【问题讨论】:

  • 如果我是你,我会制作codeandbox以获得更好的帮助
  • 如果你能把这个项目放在沙箱里,那就太好了!
  • link 。我已经把项目放在沙盒里了,请使用链接来引用它。

标签: reactjs redux react-redux redux-thunk


【解决方案1】:

但我的应用程序在调度操作的无限循环中运行 被调用,并且应用程序始终处于加载状态。 它在 30 秒内拨打了大约 1300 个电话。这是我的代码。我不能够 找出应用程序在无限循环中运行的原因。

更新:redux 功能重构为单独的组件,并使用新操作检查是否有任何 API 调用正在进行中。这是一个完美运行的sandbox

//UserActions.js
import * as types from "./actionType";
import { beginApiCall, apiCallError } from "./apiStatusAction";
import { handleResponse, handleError } from "./apiUtils";

export function fetchUsersSuccess(users) {
  return { type: types.LOAD_USERS_SUCCESS, users };
}

export function fetchUsers(url) {
  return (dispatch) => {
    dispatch(beginApiCall());
    return getUsers(url)
      .then((users) => {
        dispatch(fetchUsersSuccess(users));
      })
      .catch((error) => {
        dispatch(apiCallError(error));
        throw error;
      });
  };
}

export function getUsers(url) {
  return fetch(url).then(handleResponse).catch(handleError);
}
//apiStatusAction.js
import * as types from "./actionType";

export function beginApiCall() {
return { type: types.BEGIN_API_CALL };
}

export function apiCallError() {
return { type: types.API_CALL_ERROR };
}

这个 reducer 检查是否有任何带有子字符串 _SUCCESS 的操作仍在进行中。如果是,则initialState 加一,否则减一。

import * as types from "../actions/actionType";
import initialState from "./initialState";

function actionTypeEndsInSuccess(type) {
  return type.substring(type.length - 8) === "_SUCCESS";
}

export default function apiCallStatusReducer(
  state = initialState.apiCallsInProgress,
  action
) {
  if (action.type == types.BEGIN_API_CALL) {
    return state + 1;
  } else if (
    action.type === types.API_CALL_ERROR ||
    actionTypeEndsInSuccess(action.type)
  ) {
    return state - 1;
  }

  return state;
}

这就是您可以利用apiStatus reducer 在组件中渲染微调器的方法。

//UserContainer.js
import React, { useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { fetchUsers } from "../redux/actions/UserActions";
import Spinner from "./Spinner";

function UserContainer() {
  const userList = useSelector((state) => state.user);
  const loading = useSelector((state) => state.apiCallsInProgress > 0);

  const dispatch = useDispatch();

  const fetchUserList = () => {
    dispatch(fetchUsers("https://jsonplaceholder.typicode.com/users")).catch(
      (error) => {
        alert("Loading users failed" + error);
      }
    );
  };

  useEffect(() => {
    fetchUserList();
  }, []);

  if (loading) {
    return <Spinner />;
  }

  return (
    <div>
      <h1>Users</h1>
      {userList.map((user) => {
        return <li key={user.id}>{user.name}</li>;
      })}
    </div>
  );
}

export default UserContainer;

【讨论】:

  • 感谢您的回答。但是,如果我在 try 块内的编辑代码中编写 dispatch(decrementCount()),我的应用程序将再次在无限循环中运行,因为它是在我的原始代码中编写的。
  • 嘿@ayushi,我创建了一个sandbox。请检查一下。
  • 嗨@Ajin,该项目运行良好,因为由于使用错误而没有调用操作。我的要求是显示加载,直到两个 api 调用都完成,因为我需要调用 dispatch(incrementCount()) (在 try 开始时)和 dispatch(decrementCount()) (在 try 中返回之前),当我添加这些操作在您的 userActions.js 文件中,我再次运行在相同的错误中。删除这些功能不符合我的要求。
  • 嘿@ayushi,我认为它在翻译中丢失了。所以我创建了一个新的sandbox,它调度动作并重构了redux组件,并添加了一个新的apiCallsInProgress动作来检查是否有任何api正在进行调用。
猜你喜欢
  • 2021-08-20
  • 2018-04-24
  • 2021-12-17
  • 1970-01-01
  • 1970-01-01
  • 2018-09-20
  • 1970-01-01
  • 2018-07-31
  • 2019-02-21
相关资源
最近更新 更多