Redux分派未正确更新状态

时间:2018-12-14 17:00:21

标签: javascript reactjs redux

我的Redux减速器存在问题,无法正确更新状态。

这是我在accountActions.js文件中的动作。

// Get all accounts for specific user
export const getAccounts = () => dispatch => {
  dispatch(setAccountsLoading); // NOT WORKING
  axios
    .get("/api/plaid/accounts")
    .then(res =>
      dispatch({
        type: GET_ACCOUNTS,
        payload: res.data
      })
    )
    .catch(err =>
      dispatch({
        type: GET_ACCOUNTS,
        payload: null
      })
    );
};

// Accounts loading
export const setAccountsLoading = () => {
  return {
    type: ACCOUNTS_LOADING
  };
};

这是我的actionsReducers.js文件。

import {
  GET_ACCOUNTS,
  ACCOUNTS_LOADING,
} from "../actions/types";

const initialState = {
  accounts: [],
  loading: false
};

export default function(state = initialState, action) {
  switch (action.type) {
    case ACCOUNTS_LOADING:
      return {
        ...state,
        loading: true
      };
    case GET_ACCOUNTS:
      return {
        ...state,
        accounts: action.payload,
        loading: false
      };
    default:
      return state;
  }
}

我的dispatch(setAccountsLoading)操作中的getAccounts无法正确更新loading状态。

在我的Dashboard.js组件中,我叫getAccounts。基于loading状态,我希望显示一条“正在加载...”消息。如果getAccounts返回的帐户为零,我希望显示一条消息以添加第一个帐户。否则,如果getAccounts返回一个或多个帐户,我希望显示仪表板。

这是我的Dashboard.js组件。

import React, { Component } from "react";
import PlaidLink from "react-plaid-link";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { logoutUser } from "../../actions/authActions";
import {
  getAccounts,
  addAccount
} from "../../actions/accountActions";

import Transactions from "./Transactions";

class Dashboard extends Component {
  componentDidMount() {
    this.props.getAccounts();
  }

  // Logout
  onLogoutClick = e => {
    e.preventDefault();
    this.props.logoutUser();
  };

  // Add account
  handleOnSuccess = (token, metadata) => {
    const plaidData = {
      public_token: token,
      metadata: metadata
    };

    this.props.addAccount(plaidData);
  };

  render() {
    const { accounts, loading } = this.props.plaid;

    let dashboardContent;

    // Loading state is always false (setAccountsLoading not being called properly)
    if (loading) {
      dashboardContent = <p>Loading...</p>;
    } else if (accounts === null || Object.keys(accounts).length === 0) {
      dashboardContent = (
        <div>
          <h4>
            <b>Welcome,</b> User
          </h4>
          <p className="flow-text grey-text text-darken-1">
            To get started, link your first bank account below
          </p>
          <PlaidLink
            clientName="Mosaic"
            className="btn btn-large waves-effect waves-light hoverable blue accent-3"
            env="sandbox"
            product={["auth", "transactions"]}
            publicKey="0c3ff69a2efea552189de8b7fbbc0f"
            onSuccess={this.handleOnSuccess}
            style={{
              width: "185px",
              letterSpacing: "1.5px",
              borderRadius: "3px",
              marginTop: "1rem"
            }}
          >
            Link Account
          </PlaidLink>
          <button
            style={{
              width: "185px",
              borderRadius: "3px",
              letterSpacing: "1.5px",
              marginTop: "1rem"
            }}
            onClick={this.onLogoutClick}
            className="btn btn-large waves-effect waves-light hoverable red accent-3"
          >
            Logout
          </button>
        </div>
      );
    } else {
      dashboardContent = <Transactions accounts={accounts} />;
    }

    return (
      <div className="container">
        <div className="row">
          <div className="col s12 center-align">{dashboardContent}</div>
        </div>
      </div>
    );
  }
}

Dashboard.propTypes = {
  logoutUser: PropTypes.func.isRequired,
  getAccounts: PropTypes.func.isRequired,
  addAccount: PropTypes.func.isRequired,
  auth: PropTypes.object.isRequired,
  plaid: PropTypes.object.isRequired
};

const mapStateToProps = state => ({
  auth: state.auth,
  plaid: state.plaid
});

export default connect(
  mapStateToProps,
  { logoutUser, getAccounts, addAccount }
)(Dashboard);

加载值始终为false(在任何时候都不会切换为true)。在我的信息中心中,如果我console.log(loading),我看到两条消息表明loading为假(一条消息触发getAccounts,另一条消息getAccounts完成)。

我当前使用的一种(不正确的)解决方法是从组件本身内部调用setAccountsLoading。当我这样做时,加载值将设置为true,直到getAccounts完成为止(这会将loading设置为false)。

import React, { Component } from "react";
import PlaidLink from "react-plaid-link";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { logoutUser } from "../../actions/authActions";
import {
  getAccounts,
  setAccountsLoading,
  addAccount
} from "../../actions/accountActions";

import Transactions from "./Transactions";

class Dashboard extends Component {
  componentDidMount() {
    this.props.getAccounts();
    // Temporary workaround; this has the desired outcome
    this.props.setAccountsLoading();
  }

  // Logout
  onLogoutClick = e => {
    e.preventDefault();
    this.props.logoutUser();
  };

  // Add account
  handleOnSuccess = (token, metadata) => {
    const plaidData = {
      public_token: token,
      metadata: metadata
    };

    this.props.addAccount(plaidData);
  };

  render() {
    const { accounts, loading } = this.props.plaid;

    let dashboardContent;
    if (loading) {
      dashboardContent = <p>Loading...</p>;
    } else if (accounts === null || Object.keys(accounts).length === 0) {
      dashboardContent = (
        <div>
          <h4>
            <b>Welcome,</b> User
          </h4>
          <p className="flow-text grey-text text-darken-1">
            To get started, link your first bank account below
          </p>
          <PlaidLink
            clientName="Mosaic"
            className="btn btn-large waves-effect waves-light hoverable blue accent-3"
            env="sandbox"
            product={["auth", "transactions"]}
            publicKey="0c3ff69a2efea552189de8b7fbbc0f"
            onSuccess={this.handleOnSuccess}
            style={{
              width: "185px",
              letterSpacing: "1.5px",
              borderRadius: "3px",
              marginTop: "1rem"
            }}
          >
            Link Account
          </PlaidLink>
          <button
            style={{
              width: "185px",
              borderRadius: "3px",
              letterSpacing: "1.5px",
              marginTop: "1rem"
            }}
            onClick={this.onLogoutClick}
            className="btn btn-large waves-effect waves-light hoverable red accent-3"
          >
            Logout
          </button>
        </div>
      );
    } else {
      dashboardContent = <Transactions accounts={accounts} />;
    }

    return (
      <div className="container">
        <div className="row">
          <div className="col s12 center-align">{dashboardContent}</div>
        </div>
      </div>
    );
  }
}

Dashboard.propTypes = {
  logoutUser: PropTypes.func.isRequired,
  getAccounts: PropTypes.func.isRequired,
  addAccount: PropTypes.func.isRequired,
  auth: PropTypes.object.isRequired,
  plaid: PropTypes.object.isRequired
};

const mapStateToProps = state => ({
  auth: state.auth,
  plaid: state.plaid
});

export default connect(
  mapStateToProps,
  { logoutUser, getAccounts, setAccountsLoading, addAccount }
)(Dashboard);

有人知道为什么我的dispatch(setAccountsLoading)操作中的getAccounts没有正确更新加载状态吗?

1 个答案:

答案 0 :(得分:0)

Vassilis Pallas在评论中所述,函数调用后的括号缺失,因此您应该使用$.ajax({ url: '/API/Video/GetVideoInfo/25', dataType: 'application/json', complete: function (data) { var json = JSON.parse(data.responseText); alert(json["Views"]); }, }); 而不是dispatch(setAccountsLoading())

在另一个主题中,我想推荐Redux Promise Middleware来简化Redux中的请求使用,您只需要将请求promise分配为有效负载,此包将为您处理,分配Pending,Fulfilled和拒绝的操作取决于传递的Promise的分辨率。

这帮助我大大简化了异步Redux代码,尤其是与Type to Reducer中建议的reducers documentation of Redux Promise Middleware之类的对象配对时。