如何在 Redux 中实现缓存? [英] How do I implement caching in Redux?

查看:34
本文介绍了如何在 Redux 中实现缓存?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我的商店中已有数据,我希望避免调用 API 两次.

I would like to avoid calling an API twice if I already have the data in my store.

我如何使用 Redux 做到这一点?

How do I do this with Redux?

推荐答案

在我看来,理想的解决方案是使用 Reselect 选择器 (https://github.com/reactjs/reselect).这是一个人为的例子:

The ideal solution to this in my opinion is to use Reselect selectors (https://github.com/reactjs/reselect). Here is a contrived example:

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);

第一次运行时,一个基于某些id(也在状态中)的obj将从所有objs的列表中选择".下一次,如果输入没有改变(查看等价定义的重新选择文档),它将简单地返回上次的计算值.

The first time you run this, one obj based on some id (also in the state) will be "selected" from the list of all objs. The next time, if the inputs have not changed (look at reselect documentation for the definition of equivalence) it will simply return the computed value from last time.

您还可以选择插入不同类型的缓存,例如LRU.这有点高级,但非常可行.

You also have the option to plug-in a different type of cache, e.g. LRU. That's a bit more advanced, but very doable.

Reselect 的主要优点是它允许您进行干净的优化,而无需在 redux 中手动维护额外的状态,如果对原始数据进行了更改,您将不得不记住更新.Timo 的回答很好,但我认为它的弱点在于它不缓存昂贵的客户端计算(我知道这不是确切的问题,但这个答案是关于一般最佳实践 redux 缓存,适用于您的问题),只取.您可以执行与 Timo 建议的非常相似的操作,但合并 reselect 以获得非常整洁的解决方案.在动作创建者中,您可能有这样的事情:

The major advantage of Reselect is that it allows you to cleanly optimise without manually maintaining extra state in redux that you would then have to remember to update if a change to the original data was made. Timo's answer is good, but I would argue that the weakness is that it doesn't cache expensive client side computation (I know this wasn't the exact question, but this answer is about best practice redux caching in general, applied to your problem), only fetching. You can do something very similar to what Timo suggests, but incorporate reselect for a very tidy solution. In an action creator you could have something like this:

export const fetchObj = (dispatch, getState) => {
  if (hasObj(getState())) {
    return Promise.resolve();
  }

  return fetchSomething()
    .then(data => {
      dispatch(receiveObj(data));
      return data;
    });
};

您将有一个专门用于 hasObj 的选择器,可能基于上述选择器(我在这里这样做是为了展示如何轻松组合选择器),例如:

You would have a selector specifically for hasObj potentially based on the above selector (I do so here specifically to show how you can compose selectors easily), like:

export const hasObj = createSelector(
  [ getObj ],
  obj => !!obj
);

一旦您开始使用它与 redux 进行交互,即使对于简单的选择,在 mapStateToProps 中专门使用它也开始变得有意义,以便在将来,如果计算状态的方式发生变化,您无需修改​​所有使用该状态的组件.这方面的一个例子可能是当用于在几个不同的组件中呈现列表时拥有一个 TODO 数组.稍后在您的应用程序开发过程中,您意识到您希望默认情况下仅过滤不完整的 TODO 列表.您只需在一处更改选择器即可.

Once you start using this to interface with redux, it starts to make sense to use it exclusively in mapStateToProps even for simple selects so that at a future time, if the way that state is computed changes, you do not need to modify all of the components which use that state. An example of this might be something like having an array of TODOs when is used to render a list in several different components. Later in your application development process you realise you want to filter that list of TODOs by default to only ones that are incomplete. You change the selector in one place and you are done.

这篇关于如何在 Redux 中实现缓存?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆