React/Redux中的通用Reducers/Actions

koj*_*ow7 7 javascript reactjs redux

我试图确定如何在同一组件中引入多个数据.

我在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并在运动卡屏幕上显示数据.

基于上面的链接(和其他类似的网站),我已经想出如何在动作和减速器部分对特定运动的每个请求进行硬编码,但是如果我一直无法弄清楚如何做到这一点不提前知道运动.

根据目前的答案进一步澄清

如果有人在名为MuffiBall的API数据库中添加了新的运动,我的应用程序需要能够处理它.因此,我不能指望为添加到API的每项新运动添加新的JavaScript代码.

从数据库检索的所有体育卡都遵循相同的结构.

我当前代码的概述

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')
);
Run Code Online (Sandbox Code Playgroud)

存储/ 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)
  );
}
Run Code Online (Sandbox Code Playgroud)

动作/ 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';
Run Code Online (Sandbox Code Playgroud)

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);
      });
  };
};
Run Code Online (Sandbox Code Playgroud)

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;
  }
};
Run Code Online (Sandbox Code Playgroud)

减速器/ 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
});
Run Code Online (Sandbox Code Playgroud)

组件/ 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);
Run Code Online (Sandbox Code Playgroud)

lec*_*tor 5

退后一步,确定具有独特形状的数据类型,例如cardsstats.您将使用它自己的动作,缩减器和选择器为每个构建一个存储片.这项运动应该只是你用作你的行动和选择者的一个变量.例如

异步行动

export const fetchCards = (sport) => {
  return (dispatch) => {
    return Axios.get(`/api/${sport}/`)
      .then(response =>
        dispatch(fetchCardSuccess({ sport, data: response.data }))
      )
      .catch(error => {
        console.log(error)
        throw(error);
      });
  };
};
Run Code Online (Sandbox Code Playgroud)

减速器

export const cardReducer = (state = {}, action) => {
  switch (action.type) {
    case actionTypes.FETCH_CARD_SUCCESS:
      return { ...state, [action.sport]: action.data };
    default:
      return state;
  }
};
Run Code Online (Sandbox Code Playgroud)

卡选择器

export const getSport(state, sport) {
  return state.cards[sport];
}
Run Code Online (Sandbox Code Playgroud)

您可能需要另一个切片来管理从服务器获取的可用运动列表以及其他全局数据.