还原在哪里进行计算?

时间:2016-11-23 16:05:57

标签: javascript reactjs redux

一般性问题,但是会包含一个具体的例子:在哪里是循环通过状态/存储数据以提取计算的正确位置?

所以在这里,我需要进行一些计算以显示在统计数据中。侧边栏需要循环遍历每个客户端阵列(可能是相当多的客户端)来提取不同的道具/值并将它们全部加在一起。我是在渲染中完成它只是为了让它知道是不正确的,但是它仍然发生在组件中以及渲染之外还是在reducer中?

值得注意的是,这些将是更新的值(客户端可以标记为'服务'然后统计信息侧边栏将增加服务客户端的数量并减少要提供服务的客户端的数量) 。但这有点超出了我的一般性问题的范围。

Hows和Whys非常感谢并感谢百万!

    import React, { Component, PropTypes } from 'react';
    import { browserHistory } from 'react-router';
    import './ScheduleDayContainer.scss';
    import { connect } from 'react-redux';
    import { bindActionCreators } from 'redux';
    import * as ScheduleActions from '../../actions/ScheduleActions';

    class ScheduleDayContainer extends Component {
      static propTypes = {
        actions: PropTypes.object,
        clients: PropTypes.array.isRequired
      };

      constructor(props, context) {
        super(props, context);
      }

      componentWillMount() {
        // gets schedule (code removed because doesn't matter here) and clients array (used below)
        this.props.actions.fetchDaySchedule();
      }

      render() {
        const { clients } = this.props;

        const getStats = function (clients) {
          let totalClientsExpected = clients.length,
              totalHousehold = clients.length,
              totalServed = 0,
              totalNoShows = 0,
              totalUnverifiedExpected = 0,
              totalNotYetServed = 0;

          clients.forEach(function(client) {
            totalHousehold += client.family_count;
            client.served_at != null ? totalServed += 1 : totalNotYetServed += 1;
            // TODO: no show?
            client.verified_at === null ? totalUnverifiedExpected += 1 : null;
          });

          return {
            totalClientsExpected,
            totalHousehold,
            totalServed,
            totalNoShows,
            totalUnverifiedExpected,
            totalNotYetServed
          };
        };

        const stats = getStats(clients);

        return (
          <div className="day-container">
            <aside className="column">
              <div className="statistics-bar-container">
                <h3 className="statistics-title">Statistics</h3>
                <ul className="statistics-items">
                  <li className="statistics-item">
                    <p>Clients expected</p>
                    <span>{stats.totalClientsExpected}</span>
                  </li>
                  <li className="statistics-item">
                    <p>Total household members to be served</p>
                    <span>{stats.totalHousehold}</span>
                  </li>
                  <li className="statistics-item">
                    <p>Served</p>
                    <span>{stats.totalServed}</span>
                  </li>
                  <li className="statistics-item">
                    <p>Did not show</p>
                    <span>{stats.totalNoShows}</span>
                  </li>
                  <li className="statistics-item">
                    <p>Unverified clients expected</p>
                    <span>{stats.totalUnverifiedExpected}</span>
                  </li>
                  <li className="statistics-item">
                    <p>Yet to be served</p>
                    <span>{stats.totalNotYetServed}</span>
                  </li>
                </ul>
              </div>
            </aside>
          </div>
        );
      }
    }

    function mapStateToProps(state) {
      return {
        clients: state.schedule.clients
      };
    }

    function mapDispatchToProps(dispatch) {
      return {
        actions: bindActionCreators(ScheduleActions, dispatch)
      };
    }

    export default connect(
      mapStateToProps,
      mapDispatchToProps
    )(ScheduleDayContainer);

然后在减速器中:

    export default function scheduleReducer(state = initialState, action) {
      switch (action.type) {
        case types.FETCH_DAY:
          return {
            ...state,
            clients: action.data.clients,
            daySummary: action.data.summary,
            times: action.data.times,
            serviceDate: action.data.serviceDate,
            time: action.data.time
          };
        default:
          return state;
      }
    }

2 个答案:

答案 0 :(得分:5)

通常认可的最佳做法是尽可能地将状态保持为规范化(想想关系数据库!)。

您的派生数据可以通过称为选择器的辅助函数动态计算。如果其中一些计算费用昂贵,您可能需要考虑重新选择库。

一些阅读(抱歉,但他们解释得比我好得多!):

http://redux.js.org/docs/recipes/ComputingDerivedData.html

http://www.thinkloop.com/article/extreme-decoupling-react-redux-selectors/

https://medium.com/@adamrackis/querying-a-redux-store-37db8c7f3b0f#.gl7g9suh2

答案 1 :(得分:1)

作为一般方法,我不会将计算结果存储在您的应用程序状态中,而是在容器的mapStateToProps步骤中进行计算

这也是the sample todo list application from the redux docs遵循的方法:

const getVisibleTodos = (todos, filter) => {
  switch (filter) {
    case 'SHOW_ALL':
      return todos
    case 'SHOW_COMPLETED':
      return todos.filter(t => t.completed)
    case 'SHOW_ACTIVE':
      return todos.filter(t => !t.completed)
  }
}

const mapStateToProps = (state) => {
  return {
    todos: getVisibleTodos(state.todos, state.visibilityFilter)
  }
}

根据您的状态计算过滤后的列表或进行其他计算与高级别的观点实际上没有什么不同。

在实践中使用该方法并遇到性能问题后,您可以考虑在状态或单独的缓存中缓存结果。但是,在实际遇到任何问题only make your code more complex without real benefits之前,这样的优化。