我的应用会渲染一个视频列表,单击每个视频会提取并渲染为此视频发布的评论列表。
我正在尝试设置Redux存储以根据视频ID生成带有键的reducer,并将关联的注释存储为数组。想法是缓存这些ID,并在视频之间切换时,在按请求分页更多结果之前显示已获取的内容。
我正在使用COMMENTS REDUCER进行此操作:
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在我的动作触发并获取数据并在化简器中创建动态键之前计算了数据。结果,当我尝试映射与该键关联的注释ID列表时,出现“无法读取未定义的属性'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 | };
我尝试遵循Redux Reddit API = https://redux.js.org/advanced/example-reddit-api的示例,其中还使用[action.subreddit]动态创建了reducer密钥。
这里是否存在替代方法来生成动态密钥,或者我是否会因为当前的方法而注定要失败,因为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;
//根减速器
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);