React Redux: подключенный дочерний компонент не получает реквизиты - PullRequest
0 голосов
/ 13 декабря 2018

Я не могу понять, в чем проблема.У меня есть компонент с именем DisplayItems, который получает некоторые данные из API (список элементов).

Я использую действия Redux и промежуточное программное обеспечение для получения элементов и данных из API.Я сохраняю предметы и другие данные в хранилище избыточных данных в виде массива объектов и называю его entriesData.Фактический массив в entriesData.data.Я использую connect для подключения состояния и действий к DisplayItems 'реквизитам.

Далее у меня есть дочерний компонент с именем GalleryItemContentV1.GalleryItemContentV1 не подключен к редуксу.Он просто получает данные из DisplayItems, который проходит через массив элементов и передает каждый из них в GalleryItemContentV1.Итак, снова, DisplayItems проходит через this.props.entriesData.data и передает каждый элемент в GalleryItemContentV1 в качестве реквизита, называемого entry.

Наконец, у меня есть дочерний компонент в GalleryItemContentV1, называемый TestCom.Вот где проблема.Я также передаю предмет, который я получил от DisplyItem до TestCom.Итак, поток данных DisplayItems (подключен)> GalleryItemContentV1 (не подключен)> TestCom (подключен).

TestCom подключен к редуксу.Для обновления элемента в entriesData.data используются некоторые действия из redux.Когда я обновляю this.props.entriesData.data в TestCom, GalleryItemContentV1 получает обновленные данные просто отлично, но TestCom ничего не получает.Элемент в TestCom никогда не обновляется.

Я понял, что проблема заключается в том, когда я подключаю TestCom к избыточному.Если TestCom не подключен к редуксу, он также получает обновленные реквизиты, как и GalleryItemContentV1.

Компоненты приведены ниже.Я попытался максимально упростить их.

DisplayItems

import React, {Component} from 'react';
import GalleryItemContentV1 from './GalleryItemContentV1';
import { connect } from 'react-redux';
import {getContestEntriesPageData} from '../../actions/contest';

class DisplayItems extends Component {
  componentDidMount(){
    this.props.getContestEntriesPageData(uri, search);
  }

  render(){

    console.log('DisplayItems props', this.props);

      return (
        <div>
          <div className="card-deck thumbnails" id="card-list">
            {  this.props.entriesData.data instanceof Array ? 
                  this.props.entriesData.data.map(function(object, i){
                    return <GalleryItemContentV1 
                      entry={object} key={i} 
                      arr_key={i}
                    />;
                  }, this) : ''
              }
          </div>
        </div>
      )
  }
}

const mapStateToProps = state => (
  {
    entriesData: state.entriesData,
  }
)

const mapDispatchToProps = (dispatch) => {
  return {
    getContestEntriesPageData: (uri, search) => {
      dispatch(getContestEntriesPageData(uri, search));
    }
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(DisplayItems);

GalleryItemContentV1

import React, { Component } from 'react';
import TestCom from './TestCom';

class GalleryItemContentV1 extends Component {
  constructor(props) {
    super(props);
  }
  render() {
    return (
        <div>
        <TestCom entry={this.props.entry} />
      </div>
    );
    }
}
export default GalleryItemContentV1;

TestCom

Я выводлю результатыthis.props.entry.VotesCount (элемент из DisplayItems) в TestCom.Вот где возникает проблема.По какой-то причине, когда я подключаю TestCom к redux, его реквизиты не обновляются, но когда он отключен от Redux, то его реквизиты обновляются.

import React, {Component} from 'react';
import { connect } from 'react-redux';

class TestCom extends Component {
  constructor(props) { 
    super(props);
  }

  render(){

    console.log('TestCom props', this.props);

    return (

      <div>{this.props.entry.VotesCount}</div>

    )
  }
}

const mapStateToProps = state => (
  {
    user: state.user
  }
)
export default connect(mapStateToProps)(TestCom);

Здесь я настраиваю redux,но я не думаю, что это важно знать, так как GalleryItemContentV1 видит обновленные данные просто отлично.

import {createStore, applyMiddleware} from 'redux';
import thunk from 'redux-thunk';
import ContestReducer from '../reducers/contest';

export default function configureStore(initialState) {
  return createStore(
    ContestReducer,
    initialState,
    applyMiddleware(thunk)
  );
}

Итак, подведем итог.

DisplayItems (подключен, получает обновленные данные из хранилища в порядке)> GalleryItemContentV1 (не подключен, получает обновления в порядке)> TestCom (подключен, не получает обновления, но получает обновления, если отключен)

Вот мой редуктор, на всякий случай, если он помогает.

import * as ContestActionTypes from '../actiontypes/contest';

const initialState = {
  contest: null,
  subscriptions: [],
  user: null,
  page: null
}
export default function Contest(state=initialState, action) {
  console.log('redux action reducer: ', action)
  switch(action.type) {
    case ContestActionTypes.HANDLE_VOTE:
      const newState = { ...state };
      if (newState.entriesData) {
        const index = newState.entriesData.data.findIndex(x => x.id === action.entry.id)
        newState.entriesData.data[index].VotesCount = action.vote;
      } else {
        newState.entry.VotesCount = action.vote;
      }

      return newState

      default:
        return state;
  }
}

Я также заметил, что то же самое происходит с GalleryItemContentV1.Если я подключу его, то он перестанет получать обновления от DisplayItems / хранилища резервов.Спасибо!

Ответы [ 3 ]

0 голосов
/ 13 декабря 2018

Да, я тоже думаю, что вы мутируете своим состоянием.Ниже приведен корпус TOGGLE_TODO от редуктора.Я надеюсь, что этот фрагмент кода будет работать для вашего кода.

  case TOGGLE_TODO:
  return Object.assign({}, state, {
    todos: state.todos.map((todo, index) => {
      if (index === action.index) {
        return Object.assign({}, todo, {
          completed: !todo.completed
        })
      }
      return todo
    })
  })

Так что, в вашем случае, если идентификатор совпадает, тогда обновление выполняется с action.vote.Также читайте о глубоких и мелких копиях объектов.

0 голосов
/ 14 декабря 2018

markerikson был прав, но я публикую здесь конкретный ответ, который мне помог, здесь.

Проблема заключалась в том, что я пытался обновить массив внутри объекта (записиData - это объект, а записи - data.Data.data.будучи массивом), используя обычный метод Object.assign ({}, state, {}), когда я должен был использовать JSON.parse (JSON.stringify (state)).Мне пришлось прочитать объяснение Мозиллы (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign), чтобы понять, что происходит. Я видел решение JSON.parse раньше, но я не очень понимал мелкое и глубокое клонирование, и, каким бы ни было мелкое клонирование, я неНе думаю, что я был виновен. Оказывается, я был.

Вот мой обновленный редуктор, который отлично работает.

case ContestActionTypes.HANDLE_VOTE:
  const newState = JSON.parse(JSON.stringify(state));
  if (newState.entriesData) {
    const index = newState.entriesData.data.findIndex(x => x.id === action.entry.id)
    newState.entriesData.data[index].VotesCount = action.vote;
  } else {
    newState.entry.VotesCount = action.vote;
  }

  return newState;
0 голосов
/ 13 декабря 2018

Вы мутируете своим состоянием.Вы делаете поверхностную копию состояния верхнего уровня в этом редукторе срезов, но вы не копируете все вложенные уровни внутри.Затем подключенный компонент извлекает state.entriesData, который не изменился по ссылке.Таким образом, компонент оболочки connect считает, что состояние вообще не изменилось, и не выполняет повторную визуализацию вашего собственного компонента.

Страница документов Redux Redux в разделе «Шаблоны неизменяемого обновления» конкретно указывает на это как на распространенную ошибку.

Если обновление неизменного вложенного состояния является слишком большой болью, я бы посоветовал заглянуть в immer библиотеку неизменяемых обновлений .Кроме того, наш новый redux-starter-kit пакет использует Immer внутренне, чтобы позволить вам писать более простые редукторы.

Также см. Мой пост Idiomatic Redux: история и реализация React-Redux для фона и подробностей о том, как connect работает внутри.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...