带For循环的Redux Action无法按预期工作

时间:2018-07-20 07:40:30

标签: reactjs react-native redux react-redux

TLDR:怪异的变异。通过重新分配变量解决。但不是最有效的...


前言

我有一个名为Feed的组件已连接到redux

export class Feed extends Component {

  bookmark = (id) => {
    this.props.bookmarkItem(id).then(s=>{
      this.props.updateFeed(this.props.feed, this.props.bookmarks);
    }); //redux action with redux-thunk
  }

  render(){
      //renders card items with a bookmark button on each card
      //onPress button call this.bookmark(item.id)  
  }
}

const mapStateToProps = (state) => ({
  feed: state.app.feed,
  bookmarks: state.app.bookmarks
})

export default connect(mapStateToProps, { bookmarkItem, updateFeed })(Feed)

按下卡上的按钮时,将调用this.bookmark()函数,并调用操作this.props.bookmarkItem(id)

bookmarkItem的redux动作如下所示。

export const bookmarkItem = (item_id) => async dispatch => {
    try {

        let r = await axios.post(`/bookmark`); //api call

        let { bookmarks } = r; //get updated bookmarked items from api

        dispatch({
            type: cons.UPDATE_BOOKMARKED,
            payload: { bookmarked }
        });

        return true;
    }
    catch (err) {
        throw new Error(err);
    }
}

Redux状态看起来像这样

let app = {
  feed: [{id:1}, {id:2}, {id:3}, {id:4}],
  bookmarks:[{id:1}, {id:2}]
}

AIM

现在,我需要为Feed中的每个项目使用属性feed更新Redux State中的isBookmarked数组。

(以便我们可以显示该项目是否已添加书签)

为此,我正在调用另一个updateFeed()的redux动作

export const updateFeed = (feed, bookmarks) => dispatch => {

  console.log('checkpoint 1', feed); //CHECKPOINT 1

  for (let i = 0; i < feed.length; i++) {
    if (bookmarks.length == 0) {
      feed[i].isBookmarked = false; //mark item as NOT bookmarked
    } else {
      //check all bookmarks
      for (let p = 0; p < bookmarks.length; p++) {
        //if bookmark exists, set item in feed as isBookmarked:true
        if (bookmarks[p].id === feed[i].id)
          feed[i].isBookmarked = true; //mark item as bookmarked
      }
    }
  }

  dispatch({
    type: cons.UPDATE_FEED,
    payload: {
      feed
    }
  });
};

问题

所以我在这里面临一些问题:

  1. 即使在循环开始之前,提要对象仍在CHECKPOINT 1的Google Chrome控制台中记录具有isBookmarked属性的变异的提要。
  2. UPDATE_FEED处执行操作的有效负载是具有isBookmarked属性的,但是源的重新呈现从未发生。

麻烦的解决方法

feed操作中将t分配给新变量UPDATE_FEED正确地突变,然后发送分派调用。

但是我不确定这是否是最有效的方法。

export const updateFeed = (feed, bookmarks) => dispatch => {

  let t = JSON.parse(JSON.stringify(feed));

  console.log('checkpoint 1', feed); //CHECKPOINT 1

  for (let i = 0; i < t.length; i++) {
    if (bookmarks.length == 0) {
      t[i].isBookmarked = false; //mark item as NOT bookmarked
    } else {
      //check all bookmarks
      for (let p = 0; p < bookmarks.length; p++) {
        //if bookmark exists, set item in feed as isBookmarked:true
        if (bookmarks[p].id === t[i].id)
          t[i].isBookmarked = true; //mark item as isBookmarked
      }
    }
  }

  dispatch({
    type: cons.UPDATE_FEED,
    payload: {
      feed : t //THIS WORKS CORRECTLY
    }
  });
};

是否等到for循环异步完成才是更好的方法?

EXTRAS

Reducer看起来像这样。非常简单,仅使用新值进行更新,所有情况均由单一切换方法处理。

const initialState = {
    feed: [],
    bookmarks:[]
}


const app = (state = initialState, action) => {

    console.log('appReducer', action, JSON.stringify(state));

    switch (action.type) {
        case cons.UPDATE_BOOKMARKS:
        case cons.UPDATE_FEED:
            {
                state = {
                    ...state,
                    ...action.payload,
                }
                break;
            }

    }

    return state;
}

export default app;

1 个答案:

答案 0 :(得分:0)

  

在UPDATE_FEED操作中将提要分配给新变量t正确变异

这只是意味着,您的化简器没有创建新的状态对象。它只是改变了状态。

它使用===来检查状态树中的状态更新。

...action.payload可以处理供稿对象和嵌套元素的引用,因为它处于新状态。因此,没有状态更新。

像这样更改cons.UPDATE_FEED

state = {
           ...state,
           ...action.payload.feed,
         }