减速器中可以使用条件吗?

时间:2018-10-30 04:39:03

标签: javascript reactjs redux

就我们而言,基本上,我们需要获取一个警报列表,以显示前几个项目(在DOM中首次安装)或显示初始列表+下一个列表(单击一个load more按钮) )。

因此,我们需要在GET_ALERTS操作中执行以下条件:

case "GET_ALERTS":
    if (action.initialList) {
        newState.list = [...newState.list, action.res.data.list];
    } else {
        newState.list = newState.list.concat(
            action.res.data.list
        );
    }

当我们在Alerts组件中调用动作减少器时,我们需要指出initialList是对还是假。

例如

componentDidMount() {
    this.props.getAlerts(pageNum, true);
}

markAllAsRead() {
   // other code calling api to mark all as read
   this.props.getAlerts(pageNum, false);
}

readMore() {
  // other code that increases pageNum state counter
  this.props.getAlerts(pageNum, true);
}

无论如何,在reducer中使用条件语句是否可以?

2 个答案:

答案 0 :(得分:5)

我反对这个主意。 reducer的职责是:根据操作更新Redux状态。

以下是三种解决方法:

简便方法-将Redux状态下的列表初始化为空列表

如果您将state中的列表设置为空列表([]),则要简单得多。 您基本上可以将减速器更改为此:

case "GET_ALERTS":
    return {...state, list: [...state.list, action.res.data.list]

这将确保即使您有初始列表或要添加到列表中的更多项目,也将其追加。无需添加任何逻辑-很棒的恕我直言。

redux-thunk和将类型分为两种不同的类型

创建两个动作:GET_INIT_ALERTSGET_MORE_ALERTS

switch(action.type) {
case "GET_INIT_ALERTS":
    return {...state, list: action.res.data.list }
case "GET_MORE_ALERTS":
    return {...state, list: [...state.list, ...action.res.data.list]}
case "CHECK_READ_ALERTS":
    return {...state, read: [...state.read, ...action.res.data.list]}
}

在组件中,我将拥有:

componentDidMount() {
    this.props.getInitAlerts();
}

markAllAsRead() {
   // other code calling api to mark all as read
   this.props.getAlerts(pageNum, false);
}

readMore() {
  // other code that increases pageNum state counter
  this.props.getAlerts(pageNum);
}

借助redux-thunk在警报操作中:

export const getAlerts = (pageNum : number) => (dispatch) => {
    return apiAction(`/alerts/${pageNum}`, 'GET').then(res => dispatch({type: "GET_MORE_ALERTS", res});
}

export const getInitAlerts = () => (dispatch) => {
    return apiAction('/alerts/1', 'GET').then(res => dispatch({type: "GET_INIT_ALERTS", res});
}

我猜您是在pageNumreadMore之后更新componentDidMount。当然,您可以将该状态保存在Redux中,并将其映射回道具,并在调用getAlerts操作时将其递增。

编写自己的中间件

另一种方法是将临时/功能中间件写入concat新数据到列表中。

const concatLists = store => next => action => {
    let newAction = action
    if (action.type.includes("GET") && action.initialList) {
       newAction = {...action, concatList: action.res.data.list}
    } else if (action.type.includes("GET") {
       newAction = {...action, concatList: [...state[action.key].list, action.res.data.list]}
    }
    return next(newAction);
}

并更改您的reducer以将concatList推入状态:

case "GET_ALERTS":
    return {...state, list: action.concatList}

此外,您必须将操作更改为包含key(在这种情况下,密钥将设置为alert(或在redux中存储警报状态的密钥名称) )和initialList以确定是否合并。

顺便说一句,将这两个放在meta键下是一个好习惯。

{
  type: "GET_ALERT",
  meta: {
    initialList: true,
    key: "alert",
  },
  res: {...}
}

我希望这会有所帮助。

答案 1 :(得分:0)

我建议您采取以下行动:

  • 警报/初始化-加载初始列表
  • ALERTS / LOAD_MORE-加载下一页,然后递增pageNo,因此下一次调用将知道加载了多少页
  • ALERTS / MARK_ALL_AS_READ-服务器是否调用并重新初始化列表

商店结构

{
    list: [],
    currentPage: 0
}

并且组件代码不应跟踪pageNum

componentDidMount() {
    this.props.initAlerts();
}

markAllAsRead() {
   this.props.markAllAsRead();
}

readMore() {
   this.props.loadMore();
}