Сопоставление React (списки и ключи) добавляет старые элементы к новым элементам при рендеринге. - PullRequest
0 голосов
/ 26 февраля 2020

У меня странная проблема - когда компонент отображает, он отображает комментарии, относящиеся к сообщению, однако, когда я выбираю отображение комментариев для другого сообщения, комментарии из первого сообщения не удаляются. Он отображает комментарии к предыдущим и текущим сообщениям во втором компоненте рендера.

К вашему сведению, все идентификаторы комментариев являются уникальными и используются для списка keys ... Если я использую индекс списка для 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>

1 Ответ

0 голосов
/ 26 февраля 2020

Вместо того, чтобы передавать все 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: ...
     ...
  },
   ...
]
...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...