Redux状态更改:如果我在rootPath上,则仅更新UI

时间:2017-09-16 10:58:58

标签: reactjs redux redux-thunk

我有一个类似Reddit的应用程序。我试图建立投票功能的地方。我以为我解决了它,因为它在/

时工作得很好

但是,如果我要输入其他路径/:category :/category/:id 我可以看到一个点击发送的发送,但在这里,我必须强制更新" (f5)看到UI的变化。

API文件

export const submitPostVote = (option, id) => {
    return axios.post(`${API_URL}/posts/${id}`, {option}, { headers })
}

Action Creator(使用redux-thunk)

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>

回购

Readable Repo

2 个答案:

答案 0 :(得分:1)

我想我看到了你的问题,你在两个页面都使用相同的减速器。

  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 } }

  2. 包含单个项目的页面,在本例中是相同的reducer 需要处理不同形状的object所有的 项目的属性是传播的。

  3. { 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个减速器:
    postspost(复数和单数)。 我添加了另一个缩减器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可能会有效。)