在redux中使用带有智能/哑组件的选择器

时间:2016-10-04 06:06:27

标签: reactjs redux reselect

假设我有一个名为Forecast的最智能组件,如下所示:

function mapStateToProps(state) {
  return {
    dates: state.getIn(['forecast', 'dates']),
    isFetching: state.getIn(['forecast', 'isFetching'])
  };
}

export default connect(mapStateToProps, {
  fetchForecast
})(Forecast));

包装这样的Forecast组件:

import { getSummary, getDayForecast } from '../selectors/selectors';
export default class Forecast extends Component {

  render() {
    const { dates, isFetching } = this.props;

    return (
      <div className="row">
        {dates.map(date => (
          <Weather
            key={date}
            date={date}
            getSummary={getSummary}
            getDayForecast={getDayForecast}
          />
       ))}
      </div>
    );
  }
};

这里我将2个选择器作为道具传递给Weather组件。选择器看起来像这样:

import { createSelector } from 'reselect';
import moment from 'moment';
import { fromJS } from 'immutable';

const getDay = (state, key) => state.getIn(['forecast', 'forecast']).find(x => x.get('id') === key);

export const getSummary = createSelector(
  [getDay],
  (day => {
    const firstPeriod = day.get('periods').first();

    return fromJS({
      date: day.get('date'),
      outlook: firstPeriod.get('outlook'),
      icon: firstPeriod.get('icon')
    });
  })
);

export const getDayForecast = createSelector(
  [getDay],
  (day) => day.get('periods').map(period => fromJS({id: period.get('id') }))
);

我没有必要将这些选择器作为道具传递下来,我可以很容易地在天气组件中引用它们但我对如何在Weather组件中使用这些选择器感到困惑,因为Weather组件也是愚蠢的不会提及任何州。我只想在子组件调用的顶部使用1个容器或智能组件,或者让道具传递下去。

我能看到做这项工作的唯一方法是让一个中间的WeatherContainer组件看起来像这样:

import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';

import Weather from '../components/Weather';

import { getSummary, getDayForecast } from '../selectors/selectors';

function mapStateToProps(state, ownProps) {
  return {
    summary: getSummary(state, ownProps.date),
    detail: getDayForecast(state, ownProps.date)
  };
}

export default(connect(mapStateToProps,{}))(Weather);

我会这样称呼:

    {dates.map(date => (
      <WeatherContainer
         key={date}
         date={date}
         getSummary={getSummary}
         getDayForecast={getDayForecast}
         />
    ))}

必须创建这样的容器组件似乎完全错误。

如何在愚蠢的组件中使用选择器或者如何将它们作为道具传递下去,因为它们还需要引用状态?

1 个答案:

答案 0 :(得分:4)

在你的WeatherContainer mapStateToProps中,您使用了您的选择器,但您仍然将它们作为道具传递下来。这不是必要的。

除此之外,您应该知道创建容器WeatherContainer是正确的方法。您应该永远为组件提供选择器。它们应始终用于mapStateToProps。当状态发生变化时,React-Redux将重新评估此值,并且只要结果不同,就会告诉React更新组件。这是非常重要的一点。如果您只是抓住组件内的状态,无论是否使用选择器,那么React-Redux 不知道您正在使用此数据并且赢了&#39;当这些数据发生变化时,我们能告诉React重新呈现

现在,很多人对此事感到困惑。有愚蠢的组件,只显示东西,容器组件,的东西,如make API调用或实现各种功能。但是当你把一个愚蠢的组件和connect带到Redux时,那么这对于智能或容器组件来说并不成功。它仍然只显示东西。即使您使用mapDispatchToProps为某些事件监听器提供信息,这仍然无法使组件变得聪明。如果它包含mapStateToPropsmapDispatchToProps中的重要代码,它可能会变得聪明。但这就是生活。这些事情之间的界限只是模糊不清。

Redux Way是连接所有需要数据的东西。您可以将数据传递给子项,就像在简单的React中一样,但是您可以通过连接组件来创建更高性能的应用程序。不过,由你来决定。但是,从商店中获取数据的任何地方仍然很重要,它应放在mapStateToProps内,以便React-Redux可以密切关注数据。只要数据来自mapStateToProps

,您就可以安全地将其从父级传递给子级

这意味着将选择者传递给孩子是禁忌。此外,孩子要将状态作为参数传递给选择者?它不能很好地工作,所以它不是一个好主意。请注意,只要您connect某个组件,就不会创建一个全新的组件。只是一个简单的包装器。它应该包含非常少的代码。这不应该让你停下来。只是去吧。 connect这些组件。

我还应该提一下,您可以直接在Weather文件中连接weather.js组件。除非您要重复使用它,否则不需要保留未连接的组件。对于测试,您可以使用命名导出export未连接的组件。如果您稍后决定需要重用Weather组件,则可以随时轻松地将组件和连接调用分离为单独的文件。