【问题标题】:Redux thunk – Proper implementationRedux thunk – 正确实现
【发布时间】:2019-04-02 21:31:04
【问题描述】:

我的 redux thunk 实现导致覆盖数组数据。

显然流程中有问题,但我无法弄清楚。

基本上我有两个组件 StringInstrumentUsersListedItems

StringInstrument 将从数据库(通过 axios)获取数据以获取项目所有者列表。

将为每个所有者创建一个 UsersListedItems 组件,该组件还将通过所有者 ID 从数据库(图像)中获取数据。

所以我会说 StringInstrument 实际上创建了 UsersListedItems

这是 StringInstrument 的一些代码:

if (this.props.error) {
        return <p>Sorry! There was an error loading the items</p>;
    }
    if (this.props.isLoading) {
        return <CircularProgress/>;
    }

     return (
        <div>
            <Grid container spacing={24}>
                {this.props.itemOwner.map((item, index) => (
                    <Grid item xs={6} sm={3} key={index}>
                        <UsersListedItems
                            ownerId={item.ownerId}
                            userName={item.userName}
                            categoryId={1}>
                        </UsersListedItems>
                    </Grid >)
                )}
            </Grid>
        </div>
    );
   }
  }

const mapStateToProps = (state) => {
return {
    itemOwner: state.itemOwner.data,
    isLoading: state.itemOwner.isLoading,
    error: state.itemOwner.error
}
 }

const mapDispatchToProps = (dispatch) => {
return {
    getItemOwners: (id) => dispatch(itemAction.getItemOwners(id))
  }

这就是我实现 action 和 reducer 的方式。

export function getItemOwner(state = initState, action) {
switch (action.type) {
    case GET_ITEM_OWNER_START:
        state = Object.assign({}, state, { isLoading: true });
        break;
    case GET_ITEM_OWNER_SUCCESS:
        state = Object.assign({}, state, { data: action.payload, isLoading: false });
        break;
    case GET_ITEM_OWNER_ERROR:
        state = Object.assign({}, state, { error: action.payload, isLoading: false });
        break;
}
return state;
 }

 export function getItems(state = initState, action) {
switch (action.type) {
    case GET_ITEMS_START:
        state = Object.assign({}, state, { isLoading: true });
        break;
    case GET_ITEMS_SUCCESS:
        state = Object.assign({}, state, { data: action.payload, isLoading: false });
        break;
    case GET_ITEMS_ERROR:
        state = Object.assign({}, state, { error: action.payload, isLoading: false });
        break;
}
return state;


export const getItemOwners = (categoryId) => {
return (dispatch, getState) => {
    //make async call to database
    dispatch({ type: GET_ITEM_OWNER_START });
    axios.get('api/items/owner/category/' + categoryId)
        .then(function (response) {
            dispatch({ type: GET_ITEM_OWNER_SUCCESS, payload: response.data });
        })
        .catch(function (error) {
            dispatch({ type: GET_ITEM_OWNER_ERROR, payload: error });
        });
}
 };

  export const getItems = (categoryId, ownerId) => {
   return (dispatch, getState) => {
    dispatch({ type: GET_ITEMS_START });
    axios.get('api/items/' + categoryId + '/' + ownerId)
        .then(function (response) {
            dispatch({ type: GET_ITEMS_SUCCESS, payload: response.data });
        })
        .catch(function (error) {
            dispatch({ type: GET_ITEMS_ERROR, payload: error });
        });
}

我不确定如何管理\控制调度程序的流程,以便它适合组件结构而不覆盖收集的数据。

正如您在附加图片中看到的那样,4 个“GET_ITEM_SUCCESS”位于末尾,每个都将覆盖下一个。

希望我清楚并为这个长代码示例道歉。

谢谢

【问题讨论】:

    标签: reactjs redux redux-thunk


    【解决方案1】:

    我认为您遇到的问题是您在任何给定时间仅将其中一个项目存储在 state 中,并且每个后续调用都会破坏 state 中的内容。如果我的假设是正确的,那么解决方案是使用 categoryId 和 ownerId 作为键,将数据存储在一个对象中,其中值将是有效负载。

    首先您需要在操作中提供 categoryId 和 ownerId

    export const getItems = (categoryId, ownerId) => (dispatch, getState) => {
      dispatch({ type: GET_ITEMS_START, categoryId, ownerId });
      axios.get('api/items/' + categoryId + '/' + ownerId)
        .then(function (response) {
          dispatch({ type: GET_ITEMS_SUCCESS, payload: response.data, categoryId, ownerId });
        })
        .catch(function (error) {
          dispatch({ type: GET_ITEMS_ERROR, payload: error, categoryId, ownerId });
        });
    
    

    接下来,您需要更新 reducer 以将有效负载分配给对象

    const key = `${action.categoryId}-${action.ownerId}`; // unique key for the payload
    switch (action.type) {
        case GET_ITEMS_START:
            state = Object.assign({}, state, { isLoading: true, data: Object.assign({}, state.data, {[key]: []}) });
            break;
        case GET_ITEMS_SUCCESS:
            state = Object.assign({}, state, { data: Object.assign({}, state.data, { [key]: action.payload }), isLoading: false });
            break;
        case GET_ITEMS_ERROR:
            state = Object.assign({}, state, { error: action.payload, isLoading: false });
            break;
    }
    

    最后,您需要通过 props (redux) 将数据映射到组件的状态。然后您可以使用相同的密钥项访问这些项目[${categoryId}-${ownerId}]

    【讨论】:

    • 您好 Rob,非常感谢您的帮助。现在我可以将数据与特定所有者对齐。还有一个问题,因为我使用的是循环,所以我只能渲染一个 UsersListedItems 组件。您对此有什么更好的代码设计建议吗?谢谢
    • 我会将 UserLIstedItems 组件上的 ownerId 和 categoryId 替换为 items={items[${categoryId}-${ownerId}]} 作为道具。这样组件就可以遍历项目并呈现一个列表
    • 非常感谢。感谢您的帮助。
    猜你喜欢
    • 2018-07-05
    • 2017-10-13
    • 2019-01-01
    • 2016-08-06
    • 2019-03-23
    • 2019-12-17
    • 2021-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多