在我看来,理想的解决方案是使用Reselect 选择器(https://github.com/reactjs/reselect)。这是一个人为的例子:
import { createSelector } from 'reselect';
const getObjs = state => state.objs;
const currentObjId = state => state.currentObjId;
export const getObj = createSelector(
[ currentObjId, getObjs ],
(id, objs) => objs.get(href)
);
这样使用:
import { getObj } from './selectors';
const ExampleComponent = ({obj}) => <div>{ obj.name }</div>;
const mapStateToProps = state => ({
obj: getObj(state)
});
export default connect(mapStateToProps)(ExampleComponent);
第一次运行此程序时,将从所有objs 的列表中“选择”一个基于某些id(也处于状态)的obj。下一次,如果输入没有改变(查看重新选择文档以了解等价的定义),它将简单地返回上次的计算值。
您还可以选择插入不同类型的缓存,例如LRU。这有点高级,但非常可行。
Reselect 的主要优点是它允许您进行干净的优化,而无需在 redux 中手动维护额外的状态,如果对原始数据进行了更改,您必须记住要更新这些状态。 Timo 的回答很好,但我认为缺点是它不会缓存昂贵的客户端计算(我知道这不是确切的问题,但这个答案是关于一般最佳实践 redux 缓存,适用于您的问题),仅获取。您可以做一些与 Timo 建议的非常相似的事情,但合并 reselect 以获得非常整洁的解决方案。在动作创建器中,您可以有这样的东西:
export const fetchObj = (dispatch, getState) => {
if (hasObj(getState())) {
return Promise.resolve();
}
return fetchSomething()
.then(data => {
dispatch(receiveObj(data));
return data;
});
};
您将有一个专门针对hasObj 的选择器,可能基于上述选择器(我在这里专门展示如何轻松地编写选择器),例如:
export const hasObj = createSelector(
[ getObj ],
obj => !!obj
);
一旦你开始使用它来与 redux 交互,在 mapStateToProps 中独占使用它就开始有意义了,即使是简单的选择,这样在将来,如果计算状态的方式发生变化,你就不需要修改所有使用该状态的组件。这方面的一个例子可能是当用于在几个不同的组件中呈现一个列表时,有一个 TODO 数组。在您的应用程序开发过程的后期,您意识到您希望将 TODO 列表默认过滤为不完整的列表。您在一个地方更改选择器就完成了。