React、Redux:如何避免将数据加载到存储中两次

问题描述 投票:0回答:4

设置

我有一个 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 的理论调用?

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

reactjs redux react-redux
4个回答
3
投票

是的,我想让你的 redux 操作看起来像:

GET_CATS
GET_CATS_SUCCESS
GET_CATS_ERROR

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


1
投票

这完全取决于你如何在 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()
访问当前状态,因此检查数据是否可用是很常见的。现在这种方法带有一些样板文件,从长远来看可能会变得乏味(它需要您编写另外三个函数
loadRoomsPending
loadRoomsSuccess
loadRoomsError
)。这样您的组件就不必手动检查它。或者,如果你喜欢它更明确或更干净,你可以尝试一下我实现的中间件,我对所有这些样板感到有点沮丧,所以使用
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
,您可以在这里找到中间件。但无论如何,只要使用你认为最适合你的用例的任何东西,我想分享这项工作,因为这是一种挫败感,促使我构建一个中间件来处理它。请记住,我对您的案例做了一些假设,因此如果我完全不同意,请告诉我。


0
投票

如果我正确理解你的问题,你希望能够查看是否有一个单独的类已加载其数据。如果是,则不要再次调用 API 加载猫。

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

  1. 返回整个

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

    返回状态

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

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

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

}

}

0
投票

就我而言,我只是避免直接将数据保存到状态中,而是在对象内添加数据。 像以前一样:

const initialData = [];
state.push(...);

之后:

const initialData = {
data: []
};
state.data.push(....);
© www.soinside.com 2019 - 2024. All rights reserved.