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

How prevent duplicated list object in react redux

我的组件存在重复问题,我从 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
            })
        })
    }
}

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

在您的 FETCH_USERS 操作中,您不是用新数据替换旧数据,而是将新数据推送到当前状态。

[...state,...action.payload] 替换为 [...action.payload]

即可解决您的问题

目前有几个选项可供您选择:

  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
    }
}

还有一些其他选项需要调查,但应该能解决您的问题:)

编辑:

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

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
    }
}

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

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

在你的 FETCH_USERS 案例中尝试这样的事情:

让 newState = {...state};

newState.users = [];

newState.users.push(action.payload);

return新州;

问题在于,每次遇到减速器中的 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
    }
}