Как установить состояние Redux с помощью динамического ключа? - PullRequest
0 голосов
/ 27 декабря 2018

Мое приложение отображает список видео, нажимая на каждое видео, выбирает и отображает список комментариев, опубликованных для этого видео.

Я пытаюсь настроить свой магазин Redux для создания редуктора с ключом на основеID видео и хранить связанные комментарии в виде массива.Идея состоит в том, чтобы кэшировать эти идентификаторы и при переключении между видео отображать то, что уже было извлечено, прежде чем разбивать на страницы дополнительные результаты по запросу.

Я делаю это в КОММЕНТАРИИ СНИЖЕНИЯ:

const byVideo = (state = {}, action) => {
  const comments = (state = [], action) => {
    switch (action.type) {
      case GET_COMMENTS_SUCCESS:
        return action.comments.map(comment => comment._id);
      default:
        return state;
    }
  };

  switch (action.type) {
    case GET_COMMENTS_SUCCESS:
      return {
        [action.videoId]: comments(state[action.videoId], action)
      };
    default:
      return state;
  }
};

У меня проблема с mapStateToProps и моими селекторами.mapStateToProps вычислил данные до того, как сработало мое действие, и данные извлекаются, и в редукторе создается динамический ключ.В результате, когда я пытаюсь отобразить список идентификаторов комментариев, связанных с ключом, я получаю «Невозможно прочитать свойство map» из неопределенного.

Specifically on:
getVisibleComments
reducers/index.js:33
   30 | export const getVisibleComments = (state, videoId) => {
   31 |   const ids = fromComments.getIds(state.comments, videoId);
   32 |   console.log(ids);
 > 33 |   return ids.map(id => fromComments.getComment(state.comment, 
   id));
   34 | };

Я попытался последовать примеру ReduxReddit API = https://redux.js.org/advanced/example-reddit-api,, где ключ редуктора также создается динамически с помощью [action.subreddit].

Есть ли альтернативное решение для генерации динамического ключа здесь, или я обречен с моим текущим подходом, потому чтоmapStateToProps всегда будет вычисляться до того, как компонент полностью смонтируется, и моя выборка будет отправлена?

import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
import { connect } from 'react-redux';
import { fetchComments } from '../store/actions/comments';
import { getVisibleComments, getIsCommentsFetching } from 
'../store/reducers';
import CommentList from './commentList';

class visibleCommentList extends Component {
  componentDidMount() {
    const { vimeo_id } = this.props.match.params;
    this.props.fetchComments(vimeo_id);
  }

  render() {
    const { isFetching, comments } = this.props;

    return <CommentList isFetching={isFetching} data={comments} />;
  }
}

const mapStateToProps = (state, ownProps) => {
  const vimeo_id = ownProps.match.params.vimeo_id;
  return {
    comments: getVisibleComments(state, vimeo_id),
    isFetching: getIsCommentsFetching(state)
  };
};

export default withRouter(
  connect(
    mapStateToProps,
    { fetchComments }
  )(visibleCommentList)
);

// СНИЖЕНИЕ КОММЕНТАРИИ

import { combineReducers } from 'redux';
import {
  GET_COMMENTS_SUCCESS,
  GET_COMMENTS_REQUEST,
  GET_COMMENTS_FAILURE
} from '../actions/types';

const byIds = (state = {}, action) => {
const { comments } = action;
  switch (action.type) {
    case GET_COMMENTS_SUCCESS:
      const nextState = { ...state };
      comments.forEach(comment => (nextState[comment._id] = comment));
     return nextState;
    default:
      return state;
  }
};

const byVideo = (state = {}, action) => {
  const comments = (state = [], action) => {
    switch (action.type) {
      case GET_COMMENTS_SUCCESS:
        return action.comments.map(comment => comment._id);
      default:
        return state;
    }
  };

  switch (action.type) {
    case GET_COMMENTS_SUCCESS:
      return {
        [action.videoId]: comments(state[action.videoId], action)
      };
    default:
      return state;
  }
};

const isFetching = (state = false, action) => {
  switch (action.type) {
    case GET_COMMENTS_REQUEST:
      return true;
    case GET_COMMENTS_SUCCESS:
    case GET_COMMENTS_FAILURE:
      return false;
    default:
      return state;
  }
};

const comments = combineReducers({
  byIds,
  isFetching,
  byVideo
});

export default comments;

export const getComment = (state, id) => state.byIds[id];
export const getIds = (state, videoId) => state.byVideo[videoId];
export const getIsCommentsFetching = state => state.isFetching;

// ROOT REDUCER

import { combineReducers } from 'redux';
import createVideoIdsList, * as fromList from './createVideoIdsList';
import byIds, * as fromById from './byIds';
import comments, * as fromComments from './commentsByIds';

const listByFilter = combineReducers({
  all: createVideoIdsList('all'),
  plays: createVideoIdsList('plays'),
  likes: createVideoIdsList('likes'),
  release_date: createVideoIdsList('release_date'),
  comments: createVideoIdsList('comments')
});

const rootReducer = combineReducers({
  byIds,
  listByFilter,
  comments
});

export default rootReducer;

export const getVisibleVideos = (state, filter) => {
  const ids = fromList.getIds(state.listByFilter[filter]);
  return ids.map(id => fromById.getVideo(state.byIds, id));
};

export const getIsFetching = (state, filter) =>
  fromList.getIsFetching(state.listByFilter[filter]);

export const getVisibleComments = (state, videoId) => {
  const ids = fromComments.getIds(state.comments, videoId);
  console.log(ids);
  return ids.map(id => fromComments.getComment(state.comment, id));
};

export const getIsCommentsFetching = state =>
  fromComments.getIsCommentsFetching(state.comments); 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...