繁体   English   中英

React,Redux:如何避免将数据加载到商店两次

[英]React, Redux: how to avoid loading data into the store twice

设置

我有一个React / Redux应用程序,它从API加载cats的列表。

数据被加载到一个组件中,如下所示:

// thunk, etc omitted for clarity.
componentDidMount() {
    if(!this.props.loaded){
        this.props.actions.loadRooms();
    }
}

从这里绘制道具:

function mapStateToProps(state, ownProps) {
    return {
        cats: state.cats.items,
        loaded: state.cats.loaded
    }
}

假设如下:

1) cats将需要在一个不同的,完全独立的组件中,一个不是当前组件的子组件。

2)我无法知道哪个cats需要组件将首先安装。

实际问题

if(!this.props.loaded)有用吗? 换句话说,如果两个路由都先挂载,如果两个路由都先检查现有的商店数据,它是否可以节省我对API的理论调用?

如果检查有用,有没有更好的方法呢?

是的,我会让你的redux动作看起来像: GET_CATSGET_CATS_SUCCESSGET_CATS_ERROR

GET_CATS会将redux存储中的loading状态设置为true ,这样您就可以在相应的componentDidMount()函数中查询它,并且只在loading为false时才调用api。 我认为这是一种相当常见的方式。

如果我正确理解你的问题,你希望能够看到一个单独的类是否还加载了它的数据。 如果是,那么不要再调用API来加载猫。

有两种方法可以做到这一点,我们假设COM1和COM2是你的组件。

  1. 返回整个state而不仅仅是两个组件所需的特定变量:

    返回状态

然后引用每个组件中的猫:

this.props.COM1.cats.items
this.props.COM2.cats.items
  1. 从其他组件返回特定的cat变量。 您为每个组件执行以下操作:

function mapStateToProps(state, ownProps) {

let cats = state.COM1.cats.items;

let loaded: state.cats.loaded;

let otherCats = state.COM2.cats.items;

return {

cats,

otherCats,

loaded

}

}

这一切都取决于你如何处理在redux中的异步数据提取,如果两个兄弟组件都在监听你可以做的代表cats的状态部分:

// Component A and Component B might have something like this
// they both subscribe to the same portion of the state so, if
// data is already available then you don't need to do fetch it again.
...
componentDidMount() {
  if (this.props.cats.length === 0) {
    this.props.actions.loadRooms();
  }
}
...

如果您正在使用redux-thunk那么您可以在action级别控制它:

function loadRooms() {
  return (dispatch, getState) => {   
    if (getState().cats.length === 0) {
      dispatch(loadRoomsPending());

       fetchMyData(...args)
         .then((res) => dispatch(loadRoomsSuccess(res))
         .catch((err) => dispatch(loadRoomsError(err));
    }
  }
}


// Component A and Component B
...
componentDidMount() {
  this.props.actions.loadRooms();
}
...

再次,您可以使用getState()访问当前状态,因此检查数据是否已经可用是非常常见的。 现在这种方法带有一些样板,从长远来看可能会很繁琐(它需要你编写另外三个函数loadRoomsPendingloadRoomsSuccessloadRoomsError )。 这样您的组件就不必手动检查它。 或者如果你喜欢它更明确或更清洁你可以提供一个中间件我实现了一次尝试,我对所有这些样板都感到沮丧所以使用redux-slim-async你可以这样做:

function loadRooms() {
  return {
    types: [
      actionTypes.LOAD_ROOMS_PENDING,
      actionTypes.LOAD_ROOMS_SUCCESS,
      actionTypes.LOAD_ROOMS_ERROR,
    ],
    callAPI: fetch(...args).then(res => res.json()),
    shouldCallAPI: (state) => state.cats.length === 0,
  };
}

这可以通过符合FSA的操作为您处理所有事情,并且非常清楚发生了什么。 如果你正确设置它,你可以做得更好:

function loadRooms() {
  return {
    typePrefix: actionTypes.LOAD_ROOMS,
    callAPI: fetch(...args).then(res => res.json()),
    shouldCallAPI: (state) => state.cats.length === 0,
  };
}

这将使用格式${typePrefix}_PENDING${typePrefix}_SUCCESS${typePrefix}_ERROR触发挂起,成功和错误请求,您可以在此处找到中间件。 但是无论如何只要使用你觉得最适合你用例的任何东西,我都觉得分享这项工作是因为让我构建一个中间件来处理它是一种挫败感。 请记住,我对你的案子做了一些假设,所以如果我完全离开,请告诉我。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM