【问题标题】:React (Lists and Keys) mapping appends old items to new items on re renderReact(列表和键)映射在重新渲染时将旧项目附加到新项目
【发布时间】:2020-02-26 10:36:15
【问题描述】:

我有一个奇怪的问题 - 当组件呈现时,它会显示属于帖子的 cmets,但是当我选择显示不同帖子的 cmets 时,第一个帖子中的 cmets 不会被删除。它在第二个组件渲染中显示来自先前和当前帖子的 cmets。

仅供参考,评论 ID 都是唯一的,用于列表 keys...不知道为什么会这样。

示例代码

Redux 商店

postId: 'postId1' //this gets updated whenever I dispatch an action to view a new post (comments)

posts: [
  postId1: {
    ...post details
    comments: ['id1', 'id2'],

  },
  postId2: {
    ...post details
    comments: ['id3', 'id4'],

  }
];

comments: [
 id1: {
   ...comment details
 },
 id2: {
   ...comment details
 },
 id3: {
   ...comment details
 },
 id4: {
   ...comment details
 },
];

另一个组件中的点击事件

const handlePostClick = postId => event => {
    dispatch(selectPostRequestAction(postId));
  };

动作

export const selectPostRequestAction = postId => {
  return {
    type: types.SELECT_POST_REQUEST,
    postId,
  };
};

减速器

const initialState = {
  posts: [],
  postId: null,
  comments: [],
};

export const postManagerReducer = (state = initialState, action) => {
  switch (action.type) {
    case types.SELECT_POST_REQUEST:
      return {
        ...state,
        postId: action.postId,
      };
    default:
      return state;
  }
};

反应组件

import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';

import Comment from './comment';

const PostsContainer = (props: Props) => {
  const dispatch = useDispatch();
  const { posts, postId, comments} = useSelector(
    ({ postManager }) => postManager
  );

  if (!postId) return null;

  const post = posts[postId];

   return (
     post.comments.map((commentId, index) => (
       <Comment
         key={commentId}
         index={index}
         comment={comments[commentId]}
       />
     ))
   );
};

export default PostsContainer;

第一次渲染

<div>comment</div>
<div>comment</div>
<div>comment</div>

第二次渲染(当前结果)

//comments from second render
<div>comment</div>
<div>comment</div>
//comments from first render
<div>comment</div>
<div>comment</div>
<div>comment</div>

第二次渲染(预期结果)

//comments from second render
<div>comment</div>
<div>comment</div>

【问题讨论】:

  • 您的设计中的缺陷似乎实际上是在您发送的任何地方,因此将新的 cmets 推送到您的商店,这是我们看不到的。
  • 嘿@George 当我点击一个新的帖子链接时,我使用新的 postId 发送了一个操作,它更新了 redux 存储并重新渲染了组件......我错过了什么吗?
  • 你能分享你的选择器和你的操作吗?
  • @Domino987 帖子已更新。
  • 看起来不错,你能创建一个沙箱来重现它吗?

标签: javascript reactjs react-redux


【解决方案1】:

不要将所有posts 传递给组件,而是使用选择器/过滤器来获取您需要的单个帖子,然后将其传递给useSelector


我的实现版本如下所示:

//myComponent.js
  const { post } = useSelector(
    (state) => ({
      post: postSelector(state)
    })
  );
// selectors.js
// You can use reselect library or redux-toolkit
import { createSelector } from "reselect";
const getPosts = (state) => state.postsManager.posts
const getPostId = (state) => state.postsManager.postId

export const postSelector = createSelector(
  [getPosts, getPostId],
  (posts, postId) => {
      if(posts[postId]){ // or use some other checking
         return posts[postId];
   }

  }
);

如果您要坚持使用 列表索引,更好的 posts 状态应该如下所示:

...
posts:[
  {
     postId: ...
     postDetails: ...
     ...
  },
  {
     postId: ...
     postDetails: ...
     ...
  },
  {
     postId: ...
     postDetails: ...
     ...
  },
   ...
]
...

【讨论】:

    猜你喜欢
    • 2018-03-27
    • 1970-01-01
    • 2020-12-15
    • 2021-05-08
    • 1970-01-01
    • 2011-10-12
    • 1970-01-01
    • 1970-01-01
    • 2021-09-28
    相关资源
    最近更新 更多