如何在React Redux中防止重复的列表对象

时间:2019-02-11 15:42:24

标签: reactjs redux redux-thunk

我的组件上有一个重复的问题,我从api获取了一些伪数据。

以下哪种方法都能正常工作,但是当我更改路线并转到另一个页面并返回列出我的用户对象的页面时。每次都有我的对象的重复列表。我如何预防呢?

这是我的组件:

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux' 
import {getAllUsers} from '../actions/user'

class users extends Component {
  componentDidMount() {
    this.props.getAllUsers()
  }

  render() {
    let usersList = this.props.users.map(user => <li key={user.id}>{user.name}</li>)

    return (
      <div>
        <h1>user list</h1>
        <ul>
          {usersList}
        </ul>
      </div>
    )
  }
}

const mapStateToProps = state => ({
  users: state.users
})


function mapDispatchToProps(dispatch) {
  return {
    getAllUsers: bindActionCreators(getAllUsers, dispatch)
  }
} 

export default connect(mapStateToProps, mapDispatchToProps)(users)

这是我的减速器:

import { FETCH_USERS } from '../actions/user'

let initialState = []

export default (state = initialState, action) => {
    switch (action.type) {
        case FETCH_USERS:
            return [...state, ...action.payload]
        default:
            return state
    }
}

这是我的动作:

export const FETCH_USERS = 'FETCH_USERS';

export const getAllUsers = () => {
    return(dispatch) => {
        fetch('https://jsonplaceholder.typicode.com/users')
        .then(res => res.json())
        .then(users => {
            dispatch({
                type: FETCH_USERS,
                payload: users
            })
        })
    }
}

4 个答案:

答案 0 :(得分:2)

目前有几种选择可供您使用:

  1. 评估您是否需要执行API请求。如果您已经发出请求,是否可以仅依赖Redux存储中先前缓存的数据,还是必须依赖于每次组件安装时获取的新用户?
componentDidMount() {
    if (!this.props.users.length) {
        this.props.getAllUsers();
    }
}
  1. 如果您每次安装组件时都需要获取新数据,为什么不卸载组件时仅清除Redux存储中的数据?例如

组件:

componentWillUnmount() {
    this.props.clearUsers();
}

异径管:

import { FETCH_USERS, CLEAR_USERS } from '../actions/user'

let initialState = []

export default (state = initialState, action) => {
    switch (action.type) {
        case FETCH_USERS:
            return [...state, ...action.payload]
        case CLEAR_USERS:
            return initialState
        default:
            return state
    }
}

还有其他一些可供研究的选项,但是希望可以解决您的问题:)

编辑:

正如评论中指出的那样,作者的减速器到处都是。我希望将减速器重构为类似于以下内容的东西:

import { FETCH_USERS } from '../actions/user'

const initialState = {
    users: [],
}

export default (state = initialState, action) => {
    switch (action.type) {
        case FETCH_USERS:
            return {
                ...state,
                users: [...action.payload],
            }
        default:
            return state
    }
}

这将解决每次安装组件时用户重复的问题,同时确保在将来可以扩展化径器而不会冒整个状态被替换的风险。

答案 1 :(得分:1)

这里,每次组件为fetchUser时,您都在调用Reducer的mounting方法。 当router更改路线时,组件将变为unmount,并在返回fetchUser后再次安装。

FETCH_USERS动作内部,而不是用新动作替换旧数据,而是将新数据推送到当前状态。

[...state,...action.payload]替换为[...action.payload]即可解决您的问题

答案 2 :(得分:0)

亚历克西斯的建议只要您所在的州只有用户就可以。一旦您添加更多属性,此操作将无法正常工作,因为它将清除整个状态。

在您的FETCH_USERS案例中尝试以下操作:

let newState = {... state};

newState.users = [];

newState.users.push(action.payload);

返回newState;

答案 3 :(得分:0)

问题在于,每次遇到减速器中的FETCH_USERS案例时,都会在现有数据(状态)的顶部附加其他数据(action.payload)。由于每次安装组件时都会发生这种情况,因此它会将旧数据频繁地添加到阵列中。这是情况的更详细说明:

如果您的有效载荷等于数组[“ id1”,“ id2”],则组件首次安装时,它将进入创建状态

state = ["id1", "id2"]

下次安装该组件时,用户数组仍等于[“ id1”,“ id2”],可能是增加了新用户,或者不再有新用户。假设还添加了“ id3”。减速器将其接受并将其附加到先前的状态:

state = ["id1", "id2"]
action.payload = ["id1", "id2", "id3"]

所以...

return [...state, ...action.payload] = [ "id1", "id2", "id1", "id2", "id3" ]

添加了重复。

要解决此问题,您只需要用有效负载填充状态,而不要保留先前的状态,因为将再次检索用户列表而不会滤除先前存在的用户

return [...action.payload]

您的减速器现在应如下所示:

import { FETCH_USERS } from '../actions/user'

let initialState = []

export default (state = initialState, action) => {
    switch (action.type) {
        case FETCH_USERS:
            return [...action.payload]
        default:
            return state
    }
}