Я пытаюсь определить, как добавить несколько фрагментов данных для использования в одном компоненте.
Каждый пример, который я вижу с React / Redux, запрашивает очень конкретные данные и содержит редукторы и действия для обработки именно этого типа данных. Однако я не смог найти информацию об обработке более общих данных.
Например, у меня есть несколько различных компонентов (или категорий) на моем сайте. Одним из таких компонентов является Cards
. Таким образом, если пользователь нажимает на ссылку для /cards/hockey
, он должен запросить хоккейные данные у API (если их уже нет в магазине) и отобразить на странице «Карты». Если пользователь щелкает ссылку для /cards/football
, он должен следовать той же процедуре, проверяя, есть ли у него данные в хранилище, если не извлекает их из API, и отображая страницу Карт с этими данными.
Другой тип компонента может быть stats
со статистикой о различных спортивных командах.
Я не всегда буду знать, какие типы карт доступны заранее, поэтому я не могу жестко задавать конкретные виды спорта в своем приложении.
Так что в этом случае я хотел бы создать только два компонента: карты и статистику, но иметь динамически загружаемые данные для заполнения этих компонентов.
Сейчас у меня слишком много повторений, и оно жестко запрограммировано. Это означает, что я не могу динамически добавлять новые типы в будущем без создания нового кода для обработки каждого из этих типов.
Так, например, сейчас у меня есть /actions/footballCardActions.js и /actions/hockeyCardActions.js. Затем у меня есть /reducers/footballCardReducers.js и /reducers/hockeyCardReducers.js. У меня могут быть похожие компоненты и для компонента Stats.
Я также указываю статус, например FETCH_HOCKEY_CARDS_SUCCESS
или FETCH_FOOTBALL_CARDS_SUCCESS
.
Опять же, все они жестко запрограммированы, что затрудняет масштабируемость.
Один пример, которому я пытаюсь следовать, это https://scotch.io/tutorials/bookshop-with-react-redux-ii-async-requests-with-thunks - но опять-таки он использует очень специфические запросы данных, а не общие.
Что я могу сделать, чтобы мой код работал более обобщенно, чтобы мне не нужно было жестко кодировать определенные наборы данных. Есть ли хорошие уроки, которые имеют дело с подобной ситуацией?
Дополнительные уточнения
Одним из моих компонентов (экранов) является экран спортивной карты. Система меню (со ссылками) автоматически генерируется при загрузке сайта из API, поэтому я не всегда знаю, какие ссылки доступны. Так что здесь могут быть ссылки на хоккей, футбол, а также ряд других видов спорта, о которых я не задумывался. Если щелкнуть ссылку меню, она вызовет API для этого вида спорта и отобразит данные на экране спортивной карты.
На основе приведенной выше ссылки (и других подобных сайтов) я выяснил, как жестко закодировать каждый запрос для конкретного вида спорта в разделе действий и редукторов, но я не смог выяснить, как это сделать вообще, если я не знаю спорт раньше времени.
Дополнительные разъяснения на основе текущих ответов
Если кто-то добавляет новый вид спорта в базу данных API под названием MuffiBall, мое приложение должно быть в состоянии справиться с этим. Поэтому нельзя ожидать добавления нового кода JavaScript для каждого нового вида спорта, добавляемого в API.
Все спортивные карты, извлеченные из базы данных, имеют одинаковую структуру.
Схема моего текущего кода
index.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')
);
магазин / configureStore.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)
);
}
Действия / actionTypes
// 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);
});
};
};
redurs / 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);