我正在尝试确定如何提取多条数据以在同一组件中使用。
我在 React/Redux 中看到的每个示例都请求非常具体的数据,并且有 reducer 和 action 来处理那种确切类型的数据。但是,我无法找到有关处理更通用数据的信息。
例如,我的网站上有几个不同的组件(或类别)。其中一个组件是Cards
. 因此,如果用户点击链接,/cards/hockey
它应该从 API 请求曲棍球数据(如果它不在商店中),并在卡片页面中显示它。如果用户单击 的链接/cards/football
,则应遵循相同的过程,检查是否已存储数据,如果未从 API 中提取数据,并显示包含该数据的卡片页面。
另一种组件类型可能是stats
关于不同运动队的统计数据。
我不会总是提前知道有哪些类型的卡片可用,因此我无法在我的应用程序中硬编码特定的运动类型。
所以在这种情况下,我只想创建两个组件:cards 和 stats,但是有动态加载的数据来填充这些组件。
现在我有太多的重复,而且是硬编码的。这意味着如果不创建新代码来处理这些类型中的每一种,我将来就无法动态添加新类型。
例如,现在我有 /actions/footballCardActions.js 和 /actions/hockeyCardActions.js。然后我有 /reducers/footballCardReducers.js 和 /reducers/hockeyCardReducers.js。对于 Stats 组件,我可能也有类似的组件。
我还指定了状态,例如FETCH_HOCKEY_CARDS_SUCCESS
or FETCH_FOOTBALL_CARDS_SUCCESS
。
同样,这些都是硬编码的,这使得可扩展性变得困难。
我试图遵循的一个例子是https://scotch.io/tutorials/bookshop-with-react-redux-ii-async-requests-with-thunks - 但它再次使用非常具体的数据请求,而不是通用的。
我该怎么做才能让我的代码更通用地工作,这样我就不需要对特定的数据集进行硬编码。有没有处理类似情况的好教程?
更多说明
我的一个组件(屏幕)是运动卡屏幕。菜单系统(带链接)是在从 API 加载站点时自动生成的,所以我并不总是知道哪些链接可用。因此,可能存在曲棍球、足球以及许多我没有想到的其他运动的链接。单击菜单链接时,它将调用该运动类型的 API 并在运动卡屏幕上显示数据。
基于上面的链接(和其他类似的网站),我已经想出了如何在动作和减速器部分对特定运动的每个请求进行硬编码,但是如果我不知道如何通用地执行此操作不知道提前运动。
基于当前答案的进一步澄清
如果有人向名为 MuffiBall 的 API 数据库添加了一项新运动,我的应用程序需要能够处理它。因此,不能指望我为添加到 API 的每项新运动添加新的 JavaScript 代码。
从数据库中检索到的所有运动卡都遵循相同的结构。
我当前代码的概述
索引.js
//index.js
//Other imports here (not shown)
import Cards from './components/CardsPage'
import * as cardActions from './actions/cardActions';
import * as statsActions from './actions/statsActions';
import configureStore from './store/configureStore';
const store = configureStore();
/* Bad place to put these, and currently I am expected to know what every sport is*/
store.dispatch(hockeyActions.fetchHockey());
store.dispatch(footballActions.fetchFootball());
store.dispatch(muffiballActions.fetchMuffiball());
render(
<Provider store={store}>
<Router>
<div>
/* Navigation menu here (not shown) */
/* Currently it is manually coded, */
/* but I will be automatically generating it based on API */
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/cards/:val" component={Cards} />
<Route path="/stats/:val" component={Stats} />
</div>
</Router>
</Provider>,
document.getElementById('app')
);
存储/配置Store.js
// store/configureStore.js
import {createStore, compose, applyMiddleware} from 'redux';
// Import thunk middleware
import thunk from 'redux-thunk';
import rootReducer from '../reducers';
export default function configureStore(initialState) {
return createStore(rootReducer, initialState,
// Apply to store
applyMiddleware(thunk)
);
}
动作/动作类型
// actions/actionTypes
export const FETCH_HOCKEY_SUCCESS = 'FETCH_HOCKEY_SUCCESS';
export const FETCH_FOOTBALL_SUCCESS = 'FETCH_FOOTBALL_SUCCESS';
export const FETCH_MUFFIBALL_SUCCESS = 'FETCH_MUFFIBALL_SUCCESS';
actions/hockeyActions.js(每项运动一个这样的文件 - 需要制作一个通用文件):
// hockeyActions.js (one such file for every sport - need to make this one generic file):
import Axios from 'axios';
const apiUrl = '/api/hockey/';
// Sync Action
export const fetchHockeySuccess = (hockey) => {
return {
type: 'FETCH_HOCKEY_SUCCESS',
hockey
}
};
//Async Action
export const fetchHockey = () => {
// Returns a dispatcher function
// that dispatches an action at a later time
return (dispatch) => {
// Returns a promise
return Axios.get(apiUrl)
.then(response => {
// Dispatch another action
// to consume data
dispatch(fetchHockeySuccess(response.data))
})
.catch(error => {
console.log(error)
throw(error);
});
};
};
reducers/hockeyReducers.js(每项运动一个这样的文件 - 需要制作这个通用文件)
// reducers/hockeyReducers.js (one such file for every sport - need to make this one generic file)
import * as actionTypes from '../actions/actionTypes'
export const hockeyReducer = (state = [], action) => {
switch (action.type) {
case actionTypes.FETCH_HOCKEY_SUCCESS:
return action.hockey;
default:
return state;
}
};
减速器/ index.js
// reducers/index.js
import { combineReducers } from 'redux';
import {hockeyReducer} from './hockeyReducers'
import {footballReducer} from './footballReducers'
import {muffiballReducer} from './muffiballReducers'
export default combineReducers({
hockey: hockeyReducer,
football: footballReducer,
muffiball: muffiballReducer,
// More reducers for each sport here
});
组件/ CardsPage.js:
//components/CardsPage.js
import React from 'react';
import { connect } from 'react-redux';
class Cards extends React.Component{
constructor(props){
super(props);
this.state = {
data: this.props.data,
}
}
componentWillReceiveProps(nextProps){
this.setState({
data: nextProps.data,
})
}
render(){
return(
{/* cards displayed from this.state.data */}
)
}
}
const mapStateToProps = (state, ownProps) => {
return {
data: state[ownProps.match.params.val]
}
};
export default connect(mapStateToProps)(Cards);