我有一个类似Reddit的应用程序。我试图建立投票功能的地方。我以为我解决了它,因为它在/
但是,如果我要输入其他路径/:category
:/category/:id
我可以看到一个点击发送的发送,但在这里,我必须强制更新" (f5)看到UI的变化。
export const submitPostVote = (option, id) => {
return axios.post(`${API_URL}/posts/${id}`, {option}, { headers })
}
export function postPostVote(option, id) {
const request = API.submitPostVote(option, id)
return (dispatch) => {
request.then(({data}) => {
dispatch({type: SUBMIT_POST_VOTE, payload: data})
});
};
}
export default function(state = {}, action) {
const {payload} = action
switch (action.type){
case SUBMIT_POST_VOTE:
return {...state, [payload.id]: payload}
import { postPostVote } from '../actions';
<span
className='fa fa-angle-up voteArrow'
onClick={() => this.props.postPostVote('upVote', id)}
></span>
export default connect(null, {postPostVote})(PostComponent);
import PostComponent from './Post_PostComponent';
<div>
<Container>
<PostComponent
key={id}
id={id}
title={title}
author={author}
voteScore={voteScore}
category={category}
timestamp={timestamp}
redirect={false}
/>
</Container>
</div>
答案 0 :(得分:1)
我想我看到了你的问题,你在两个页面都使用相同的减速器。
包含项目列表的页面,在本例中为reducer形状
是一个对象,每个键都是id
项,它是object
同时包含该项目的所有数据。
{
'6ni6ok3ym7mf1p33lnez': {
author: "thingone",
body: "Just kidding. It takes more than 10 minutes to learn technology.",
category: "redux",
deleted: false,
id: "6ni6ok3ym7mf1p33lnez",
timestamp: 1468479767190,
title: "Learn Redux in 10 minutes!",
voteScore: 6
}
}
包含单个项目的页面,在本例中是相同的reducer
需要处理不同形状的object
所有的
项目的属性是传播的。
{
author: "thingone",
body: "Just kidding. It takes more than 10 minutes to learn technology.",
category: "redux",
deleted: false,
id: "6ni6ok3ym7mf1p33lnez",
timestamp: 1468479767190,
title: "Learn Redux in 10 minutes!",
voteScore: 6
}
例如,如果您要更改reducer_posts.js
返回的对象的形状:
由此:
case SUBMIT_POST_VOTE:
return {...state, [payload.id]: payload}
对此:
case SUBMIT_POST_VOTE:
return {...state, ...payload}
您会注意到,现在第一个页面列表运行不正常,但第二页显示单个项目正在按预期工作。
所以你应该重新考虑减速器的形状或将减速器分成两部分。
修改强>
我很好奇处理这种情况的最佳结构是什么,所以我冒昧地为你改变一些东西。
所以我决定将你的reducer_posts.js
分成2个减速器:
posts
和post
(复数和单数)。
我添加了另一个缩减器reducer_post.js
这是代码:
import { POST_GET_POST, SUBMIT_POST_VOTE } from '../actions/action_constants';
export default function (state = {}, action) {
const { payload } = action
switch (action.type) {
case SUBMIT_POST_VOTE:
return { ...state, ...payload }
case POST_GET_POST:
return payload;
default:
return state;
}
}
旧的缩减器reducer_posts.js
现在看起来像这样:
import _ from 'lodash';
import { POST_GET_POSTS, SUBMIT_POST_VOTE } from '../actions/action_constants';
export default function(state = {}, action) {
const {payload} = action
switch (action.type){
case SUBMIT_POST_VOTE:
return {...state, [payload.id]: payload}
case POST_GET_POSTS:
return _.mapKeys(payload, 'id');
default:
return state;
}
}
当然不要忘记将其添加到rootReducer
:
export const rootReducer = combineReducers({
routing: routerReducer,
posts: PostsReducer,
post: PostReducer, // our new reducer
comments: CommentReducer,
categories: CategoriesReducer,
});
基本上,一个将处理多个帖子对象形状,一个将处理单个帖子对象形状。
现在,您应该更改的唯一内容是mapStateToProps
组件中的Post_DetailedPost.js
它不使用posts
缩减器,而是使用post
缩减器:
function mapStateToProps(state) {
return {post: state.post}
}
这可以解决您的问题。
答案 1 :(得分:1)
我认为问题是这样的:投票操作的reducer逻辑假定状态有一些特定的结构(一个带有帖子的对象,其id为关键。),但是getPost的reducer逻辑行动打破了这一假设。
查看回购中的代码,特别是&#34; DetailedPost&#34;。这看起来有点偏,但我可能错了:
// in reducer_posts.js
case POST_GET_POST:**strong text**
return payload;
我认为你会从API获得一篇特定的帖子。如果是这样,这种回归基本上会摆脱该州的其他一切。 (所有其他帖子)。也许这就是你想要的,但我从未见过减速器以这种方式改变了国家的结构。我原以为它会像
那样case POST_GET_POST:
return {...state, [payload.id]: payload}
(如果您真的希望其他帖子消失,可能没有...state
。)。
但是,您还必须更改详细视图的mapStateToProps
。您应该能够从第二个参数访问路径道具(注意:ownProps
上的确切路径可能不同。我不记得网址在哪里存储的确切内容)
// in Post_DetailedPost.js
function mapStateToProps(state, ownProps) {
const idFromURL = ownProps.id; // or maybe ownProps.match.params.id
return {post: state.posts[idFromURL]};
}
这实际上可能是问题所在,因为你赞成一个帖子,你得到了新的(更新的)帖子,你改变了这样的状态。
case SUBMIT_POST_VOTE:
return {...state, [payload.id]: payload}
但这并不是您过去将帖子传递给组件的状态结构。因此,您无法将更新的道具传递到详细信息视图。 (但建议编辑mapStateToProps
可能会有效。)