我已经使用了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")
);
您可以将许多代码简化为单个可重用组件,根据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;
当然 - 我会创建一个帮助函数来删除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 }
}