Как предотвратить дублирование объекта списка в реагирующем редуксе - PullRequest
0 голосов
/ 11 февраля 2019

У меня проблема с дублированием на моем компоненте, из-за которой я получаю некоторые фиктивные данные из 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 голосов
/ 11 февраля 2019

Проблема заключается в том, что каждый раз, когда происходит обращение к случаю 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
    }
}
0 голосов
/ 11 февраля 2019

На данный момент доступно несколько вариантов:

  1. Оцените, нужно ли выполнить запрос API.Если вы уже сделали запрос, можете ли вы просто полагаться на ранее кэшированные данные в своем хранилище Redux или вам нужно полагаться на то, что новые пользователи выбираются при каждом монтировании компонента?
componentDidMount() {
    if (!this.props.users.length) {
        this.props.getAllUsers();
    }
}
Если вам нужно получать новые данные каждый раз, когда компонент монтируется, почему бы просто не очистить данные в хранилище 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
    }
}

Это решило бы проблему дублирования пользователей при каждом монтировании компонента, в то же время гарантируя, что редуктор может быть расширен вбудущее, не рискуя тем, что государство будет заменено.

0 голосов
/ 11 февраля 2019

Предложение Alexis работает нормально, если в вашем штате есть только пользователи.Как только вы добавите больше свойств, это больше не будет работать, поскольку очищает все состояние.

Попробуйте что-то подобное в вашем случае FETCH_USERS:

let newState = {...state};

newState.users = [];

newState.users.push (action.payload);

return newState;

0 голосов
/ 11 февраля 2019

Здесь вы вызываете fetchUser метод вашего редуктора каждый раз, когда ваш компонент равен mounting.Когда ваш router меняет маршрут, компоненты unmount и перемонтирование после возврата, fetchUser вызывает снова.

Внутри вашего действия FETCH_USERS вместо замены старых данных новыми, которые выподталкивают новые данные к текущему состоянию.

Ваша проблема будет решена путем замены [...state,...action.payload] на [...action.payload]

...