在 redux 中使用带有 smart/dumb 组件的选择器
Using selectors with smart/dumb components in redux
假设我有一个名为 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 个选择器作为 props 传递给 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') }))
);
我不必将这些选择器作为道具传递下去,我可以轻松地在天气组件中引用它们,但我对如何在天气组件中使用这些选择器感到困惑,因为天气组件也是愚蠢的,不会对状态有任何参考。我只希望在顶部有 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}
/>
))}
必须创建这样的容器组件似乎是完全错误的。
如何在哑组件中使用选择器,或者如何将它们作为 props 传递,同时记住它们也需要引用状态?
在您的 WeatherContainer
mapStateToProps
中,您使用了选择器,但仍然将它们作为道具传递下去。这不是必需的。
除此之外,您应该知道创建容器 WeatherContainer
是处理事情的正确方法。你应该永远不要给一个组件一个选择器。它们应始终在 mapStateToProps
中使用。 React-Redux 将在状态更改时重新评估它,并会告诉 React 在结果不同时更新您的组件。这是非常重要的一点。如果你只是获取组件内部的状态,无论是否使用选择器,那么 React-Redux 不知道 你正在使用这个数据并且 赢了' 当数据改变时,我们可以告诉 React 重新渲染。
现在,很多人都对这件事感到困惑。有仅显示内容的哑组件,以及 执行 内容的容器组件,例如进行 API 调用或实现各种功能。但是当你把一个哑组件 connect
放到 Redux 中时,这就不会成为一个智能或容器组件。它仍然只显示东西。即使您使用 mapDispatchToProps
为其提供一些事件侦听器,这仍然不能真正使组件变得智能。我猜如果它在 mapStateToProps
或 mapDispatchToProps
中包含重要代码,它可能会变得聪明。但这就是生活。这些东西之间的界限很模糊。
Redux Way 是连接所有需要数据的东西。您当然可以将数据向下传递给 children,就像在普通 React 中一样,但是您可以通过连接组件来创建性能更高的应用程序。尽管如此,还是由您来决定。但仍然重要的是,无论您从商店中获取数据的任何地方,都应将其放在 mapStateToProps
中,以便 React-Redux 可以关注数据。只要数据来自 mapStateToProps
.
,您就可以安全地将它从 parent 传递到 child
这意味着将选择器传递给 children 是 no-no。另外,child 在哪里获取状态作为参数传递给选择器?它效果不佳,所以这不是一个好主意。请注意,每当您 connect
一个组件时,您并不是在创建一个全新的组件。只是一个简单的包装器。它应该在很少的几行中包含很少的代码。这不应该让你停下来。去吧。 connect
那些组件。
我还应该提一下,您可以直接在 weather.js
文件中连接 Weather
组件。除非您要重用它,否则没有必要保留未连接的组件。为了进行测试,您可以 export
具有命名导出的未连接组件。如果稍后您决定需要重用 Weather
组件,您始终可以轻松地将组件和连接调用分离到单独的文件中。
假设我有一个名为 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 个选择器作为 props 传递给 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') }))
);
我不必将这些选择器作为道具传递下去,我可以轻松地在天气组件中引用它们,但我对如何在天气组件中使用这些选择器感到困惑,因为天气组件也是愚蠢的,不会对状态有任何参考。我只希望在顶部有 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}
/>
))}
必须创建这样的容器组件似乎是完全错误的。
如何在哑组件中使用选择器,或者如何将它们作为 props 传递,同时记住它们也需要引用状态?
在您的 WeatherContainer
mapStateToProps
中,您使用了选择器,但仍然将它们作为道具传递下去。这不是必需的。
除此之外,您应该知道创建容器 WeatherContainer
是处理事情的正确方法。你应该永远不要给一个组件一个选择器。它们应始终在 mapStateToProps
中使用。 React-Redux 将在状态更改时重新评估它,并会告诉 React 在结果不同时更新您的组件。这是非常重要的一点。如果你只是获取组件内部的状态,无论是否使用选择器,那么 React-Redux 不知道 你正在使用这个数据并且 赢了' 当数据改变时,我们可以告诉 React 重新渲染。
现在,很多人都对这件事感到困惑。有仅显示内容的哑组件,以及 执行 内容的容器组件,例如进行 API 调用或实现各种功能。但是当你把一个哑组件 connect
放到 Redux 中时,这就不会成为一个智能或容器组件。它仍然只显示东西。即使您使用 mapDispatchToProps
为其提供一些事件侦听器,这仍然不能真正使组件变得智能。我猜如果它在 mapStateToProps
或 mapDispatchToProps
中包含重要代码,它可能会变得聪明。但这就是生活。这些东西之间的界限很模糊。
Redux Way 是连接所有需要数据的东西。您当然可以将数据向下传递给 children,就像在普通 React 中一样,但是您可以通过连接组件来创建性能更高的应用程序。尽管如此,还是由您来决定。但仍然重要的是,无论您从商店中获取数据的任何地方,都应将其放在 mapStateToProps
中,以便 React-Redux 可以关注数据。只要数据来自 mapStateToProps
.
这意味着将选择器传递给 children 是 no-no。另外,child 在哪里获取状态作为参数传递给选择器?它效果不佳,所以这不是一个好主意。请注意,每当您 connect
一个组件时,您并不是在创建一个全新的组件。只是一个简单的包装器。它应该在很少的几行中包含很少的代码。这不应该让你停下来。去吧。 connect
那些组件。
我还应该提一下,您可以直接在 weather.js
文件中连接 Weather
组件。除非您要重用它,否则没有必要保留未连接的组件。为了进行测试,您可以 export
具有命名导出的未连接组件。如果稍后您决定需要重用 Weather
组件,您始终可以轻松地将组件和连接调用分离到单独的文件中。