reactjs - 如何创建一个更短的可以处理多种动作类型的 redux-promise-middleware reducer 函数?
问题描述
我已经使用 redux-promise-middleware 和 react 和 redux 来构建一个具有多个按钮的应用程序(每个按钮都有自己独特的 ajax 请求,将相应地更新状态)
我开始为我正在制作的众多按钮中的三个制作 dataReducer。dataReducer 已经超过 100 行,为其余按钮制作这个 reducer 也非常繁琐。
有没有更有效的方法来创建这个 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;
}
};
完整代码(此处为代码沙箱)
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")
);
解决方案
您的许多代码可以简化为单个可重用组件,该组件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;
推荐阅读
- ios - 如何在 podfile 中指定 CocoaPods 存储库分支
- python - 两个非常相似的正则表达式,其他找不到匹配
- notepad++ - 如何在记事本++中搜索和替换匹配的命中
- rest - Autodesk Forge,.Net API POST 方法不返回新对象 ID
- java - 使用 Microsoft graph Java Sdk 创建发布请求以将用户添加到组
- java - 如何减少 Spring Boot 控制器中的重复代码
- docker - MDNS 从 Kubernetes 内广播?
- javascript - Javascript工具提示没有随着鼠标移动而移动
- node.js - 同一组件中的方法 - 自动更新
- jquery - 在网格中的幻灯片切换上保持单元格 100% 的高度