如何创建一个可以处理多种动作类型的更短的redux-promise-middleware reducer函数?

问题描述 投票:0回答:2

我已经使用了redux-promise-middleware和react和redux来构建一个有几个按钮的应用程序(每个按钮都有自己独特的ajax请求,相应地更新状态)

我开始为我正在制作的许多按钮中的三个制作dataReducer。 dataReducer已经超过100行,并且为剩余的按钮制作这个减速器也非常繁琐。

是否有更有效的方法来创建此dataReducer函数并缩短,同时确保dataReducer函数保持纯净

const dataReducer = (state = dataInitialState, action) => {
  console.log({ action_type: action.type });
  switch (action.type) {
    case "UPDATE_URL_ONE_PENDING":
      return {
        ...state,
        url_one: {
          ...state["url_one"],
          error: false,
          success: false,
          loading: true
        }
      };
    case "UPDATE_URL_ONE_FULFILLED":
      console.log({ payload: action["payload"] });
      return {
        ...state,
        url_one: {
          ...state["url_one"],
          error: false,
          success: true,
          loading: false,
          payload: action["payload"]
        }
      };
    case "UPDATE_URL_ONE_REJECTED":
      return {
        ...state,
        url_one: {
          ...state["url_one"],
          error: true,
          success: false,
          loading: false
        }
      };
    case "UPDATE_URL_TWO_PENDING":
      return {
        ...state,
        url_two: {
          ...state["url_two"],
          error: false,
          success: false,
          loading: true
        }
      };
    case "UPDATE_URL_TWO_FULFILLED":
      return {
        ...state,
        url_two: {
          ...state["url_two"],
          error: false,
          success: true,
          loading: false,
          payload: action["payload"]
        }
      };
    case "UPDATE_URL_TWO_REJECTED":
      return {
        ...state,
        url_two: {
          ...state["url_two"],
          error: true,
          success: false,
          loading: false
        }
      };
    case "UPDATE_URL_THREE_PENDING":
      return {
        ...state,
        url_three: {
          ...state["url_three"],
          error: false,
          success: false,
          loading: true
        }
      };
    case "UPDATE_URL_THREE_FULFILLED":
      return {
        ...state,
        url_three: {
          ...state["url_three"],
          error: false,
          success: true,
          loading: false,
          payload: action["payload"]
        }
      };
    case "UPDATE_URL_THREE_REJECTED":
      return {
        ...state,
        url_three: {
          ...state["url_three"],
          error: true,
          success: false,
          loading: false
        }
      };
    default:
      return state;
  }
};

完整代码(Code Sandbox Here

import React from "react";
import ReactDOM from "react-dom";
import { Provider, connect } from "react-redux";
import { createStore, applyMiddleware, combineReducers } from "redux";
import thunk from "redux-thunk";
import promise from "redux-promise-middleware";

//Action Creator
function updateData(url, type) {
  console.log({ url, type });
  return dispatch => {
    dispatch({
      type: type,
      payload: $.ajax({
        type: "GET",
        url: url,
        dataType: "json",
        async: false
      })
    });
  };
}

//App Component
class App extends React.Component {
  render() {
    return (
      <div>
        <button
          onClick={() => {
            console.log({ props: this.props });
          }}
        >
          Check Props
        </button>
        <button
          onClick={() => {
            this.props.updateData(
              "https://api.iextrading.com/1.0/stock/market/batch?symbols=TSLA&types=quote,stats,news,chart&range=1m&last=5",
              "UPDATE_URL_ONE"
            );
          }}
        >
          UPDATE URL ONE
        </button>
        <button
          onClick={() => {
            this.props.updateData(
              "https://api.iextrading.com/1.0/stock/market/batch?symbols=GE&types=quote,stats,news,chart&range=1m&last=5",
              "UPDATE_URL_TWO"
            );
          }}
        >
          UPDATE_URL_TWO
        </button>
        <button
          onClick={() => {
            this.props.updateData(
              "https://api.iextrading.com/1.0/stock/market/batch?symbols=PZZA&types=quote,stats,news,chart&range=1m&last=5",
              "UPDATE_URL_THREE"
            );
          }}
        >
          UPDATE_URL_THREE
        </button>
        <button
          onClick={() => {
            this.props.updateData(
              "https://api.iextrading.com/1.0/stock/market/batch?symbols=PZZA&types=quote,stats,news,chart&range=1m&last=5",
              "UPDATE_URL_FOUR"
            );
          }}
        >
          UPDATE_URL_FOUR
        </button>
        <button
          onClick={() => {
            this.props.updateData(
              "https://api.iextrading.com/1.0/stock/market/batch?symbols=PZZA&types=quote,stats,news,chart&range=1m&last=5",
              "UPDATE_URL_FIVE"
            );
          }}
        >
          UPDATE_URL_FIVE
        </button>
        <button
          onClick={() => {
            this.props.updateData(
              "https://api.iextrading.com/1.0/stock/market/batch?symbols=PZZA&types=quote,stats,news,chart&range=1m&last=5",
              "UPDATE_URL_SIX"
            );
          }}
        >
          UPDATE_URL_SIX
        </button>
        <button
          onClick={() => {
            this.props.updateData(
              "https://api.iextrading.com/1.0/stock/market/batch?symbols=PZZA&types=quote,stats,news,chart&range=1m&last=5",
              "UPDATE_URL_SEVEN"
            );
          }}
        >
          UPDATE_URL_SEVEN
        </button>
        <button
          onClick={() => {
            this.props.updateData(
              "https://api.iextrading.com/1.0/stock/market/batch?symbols=PZZA&types=quote,stats,news,chart&range=1m&last=5",
              "UPDATE_URL_EIGHT"
            );
          }}
        >
          UPDATE_URL_EIGHT
        </button>
        <button
          onClick={() => {
            this.props.updateData(
              "https://api.iextrading.com/1.0/stock/market/batch?symbols=PZZA&types=quote,stats,news,chart&range=1m&last=5",
              "UPDATE_URL_NINE"
            );
          }}
        >
          UPDATE_URL_NINE
        </button>
        <button
          onClick={() => {
            this.props.updateData(
              "https://api.iextrading.com/1.0/stock/market/batch?symbols=PZZA&types=quote,stats,news,chart&range=1m&last=5",
              "UPDATE_URL_TEN"
            );
          }}
        >
          UPDATE_URL_TEN
        </button>
      </div>
    );
  }
}

const mapStateToProps = state => state;
const mapDispatchToProps = dispatch => {
  return {
    updateData: (data, type) => {
      dispatch(updateData(data, type));
    }
  };
};

const AppEnhanced = connect(
  mapStateToProps,
  mapDispatchToProps
)(App);

//reducer below that will determine how the state updates based on the action reducer above

const dataInitialState = {
  url_one: { error: false, success: false, loading: true, payload: [] },
  url_two: { error: false, success: false, loading: true, payload: [] },
  url_three: { error: false, success: false, loading: true, payload: [] },
  url_four: { error: false, success: false, loading: true, payload: [] },
  url_five: { error: false, success: false, loading: true, payload: [] },
  url_size: { error: false, success: false, loading: true, payload: [] },
  url_seven: { error: false, success: false, loading: true, payload: [] },
  url_eight: { error: false, success: false, loading: true, payload: [] },
  url_nine: { error: false, success: false, loading: true, payload: [] },
  url_ten: { error: false, success: false, loading: true, payload: [] }
};

const dataReducer = (state = dataInitialState, action) => {
  console.log({ action_type: action.type });
  switch (action.type) {
    case "UPDATE_URL_ONE_PENDING":
      return {
        ...state,
        url_one: {
          ...state["url_one"],
          error: false,
          success: false,
          loading: true
        }
      };
    case "UPDATE_URL_ONE_FULFILLED":
      console.log({ payload: action["payload"] });
      return {
        ...state,
        url_one: {
          ...state["url_one"],
          error: false,
          success: true,
          loading: false,
          payload: action["payload"]
        }
      };
    case "UPDATE_URL_ONE_REJECTED":
      return {
        ...state,
        url_one: {
          ...state["url_one"],
          error: true,
          success: false,
          loading: false
        }
      };
    case "UPDATE_URL_TWO_PENDING":
      return {
        ...state,
        url_two: {
          ...state["url_two"],
          error: false,
          success: false,
          loading: true
        }
      };
    case "UPDATE_URL_TWO_FULFILLED":
      return {
        ...state,
        url_two: {
          ...state["url_two"],
          error: false,
          success: true,
          loading: false,
          payload: action["payload"]
        }
      };
    case "UPDATE_URL_TWO_REJECTED":
      return {
        ...state,
        url_two: {
          ...state["url_two"],
          error: true,
          success: false,
          loading: false
        }
      };
    case "UPDATE_URL_THREE_PENDING":
      return {
        ...state,
        url_three: {
          ...state["url_three"],
          error: false,
          success: false,
          loading: true
        }
      };
    case "UPDATE_URL_THREE_FULFILLED":
      return {
        ...state,
        url_three: {
          ...state["url_three"],
          error: false,
          success: true,
          loading: false,
          payload: action["payload"]
        }
      };
    case "UPDATE_URL_THREE_REJECTED":
      return {
        ...state,
        url_three: {
          ...state["url_three"],
          error: true,
          success: false,
          loading: false
        }
      };
    default:
      return state;
  }
};

const reducers = combineReducers({
  data: dataReducer
});
const store = createStore(reducers, applyMiddleware(thunk, promise));

ReactDOM.render(
  <Provider store={store}>
    <AppEnhanced />
  </Provider>,
  document.getElementById("root")
);
reactjs redux react-redux redux-promise-middleware
2个回答
0
投票

您可以将许多代码简化为单个可重用组件,根据state请求的成功或失败更新其自己的本地ajax。开发人员经常跑到redux而不理解为什么。在这种情况下/示例中,您不需要它。但是,如果您的应用程序被大量嵌套并在多个父组件之间拆分,那么redux可能是一个可行的选择。无论哪种方式,它仍然可以简化为单个可重用组件。

工作示例:https://codesandbox.io/s/0x0478x4wp


index.js

import React, { Fragment } from "react";
import { render } from "react-dom";
import StockButton from "./components/StockButton";

const App = () => (
  <Fragment>
    <StockButton symbol="PZZA" />
    <StockButton symbol="AAPL" />
    <StockButton symbol="MSFT" />
  </Fragment>
);

render(<App />, document.getElementById("root"));

组件/ StockButton

import React, { Component } from "react";
import PropTypes from "prop-types";
import axios from "axios";
import Placeholder from "../Placeholder";

const initialState = {
  error: false,
  success: false,
  loading: false,
  payload: []
};

class StockButton extends Component {
  state = { ...initialState };

  componentDidMount = () => this.fetchData();

  fetchData = () => {
    this.setState({ loading: true }, () => {
      const { symbol } = this.props;
      const URL = `https://api.iextrading.com/1.0/stock/market/batch?symbols=${symbol}&types=quote,stats,news,chart&range=1m&last=5`;
      axios
        .get(URL)
        .then(({ data }) => this.setState({ loading: false, payload: data }))
        .catch(error => this.setState({ ...initialState, error }));
    });
  };

  render = () =>
    this.state.error ? (
      <p>Error loading data!</p>
    ) : this.state.loading ? (
      <Placeholder />
    ) : (
      <div>
        <button onClick={this.fetchData}>Update {this.props.symbol}</button>
        <pre style={{ width: 500, height: 300, overflowY: "auto" }}>
          <code>{JSON.stringify(this.state.payload, null, 4)}</code>
        </pre>
      </div>
    );
}

StockButton.propTypes = {
  symbol: PropTypes.string.isRequired
};

export default StockButton;

组件/占位符

import React, { Fragment } from "react";

const Placeholder = () => (
  <Fragment>
    <button style={{ width: 95, height: 24 }}>Loading</button>
    <pre style={{ width: 500, minHeight: 300, overflowY: "scroll" }} />
  </Fragment>
);

export default Placeholder;

0
投票

当然 - 我会创建一个帮助函数来删除reducer中的一些重复,如下所示:

   const updateUrl = (state, urlKey, error, success, loading, payload) => {
      return {
        ...state,
        [urlKey]: { // 'computed key'
          ...state[urlKey],
          error, success, loading, payload
        }
    }

然后你可以像这样使用它:

    const dataReducer = (state = dataInitialState, action) => {
      console.log({ action_type: action.type });
      switch (action.type) {
        case "UPDATE_URL_ONE_PENDING":
          // call our helper func
          return updateUrl(state, "url_one", false, false, true);
        case "UPDATE_URL_ONE_FULFILLED":
          console.log({ payload: action["payload"] });
          return updateUrl(state, "url_one", false, true, false, action.payload);
          ...

然而,似乎许多减速器动作是不必要的并且可以合并 - 例如上面的两个动作很容易变成一个:

case "UPDATE_URL_ONE":
  // call our helper func
  return updateUrl(state, "url_one", action.error, action.success, action.loading);

您可以使用简单的“UPDATE_URL”操作进一步删除单个操作。

EG

case "UPDATE_URL":
  // call our helper func
  return updateUrl(state, action.url, action.error, action.success, action.loading, action.payload);

在你的actions文件中,你可以有一个通用的updateUrlAction,如下所示:

const updateUrlaction = (url, error, success, loading, payload) => dispatch => {
  dispatch( {
    type: 'UPDATE_URL',
    url, error, success, loading, payload }
}
© www.soinside.com 2019 - 2024. All rights reserved.