Состояние обновляется, но компонент не перерисовывается

Я использую карту MUI для отображения всех сообщений вошедшего в систему пользователя. Карта MUI имеет свойство разворачиваться или сворачиваться в зависимости от true или false. На каждой карточке я даю ключ expanded, изначально заданный как пустая строка. По щелчку значка я устанавливаю expanded этого конкретного сообщения в непустую строку. Если расширенное поле является непустой строкой, тогда я устанавливаю true в сворачивании, иначе false.

Состояние обновляется, как и ожидалось, но компонент не выполняет повторную визуализацию, и в результате развертывание или свертывание не работает.

При первоначальном рендеринге я устанавливаю состояние публикации и добавляю к нему расширенное поле.

useEffect(() => {
    let parr = [];
    const unsub = database.posts
      .orderBy("createdAt", "desc")
      .onSnapshot((querySnapshot) => {
        parr = [];
        querySnapshot.forEach((doc) => {
          let data = { ...doc.data(), postId: doc.id, expanded: "" };
          parr.push(data);
        });
        setPosts(parr);
      });
    return unsub;
}, []);

Функция с именем handleComment отвечает за установку expanded в пустую или непустую строку.

  const handleComment = (id) => {
    for (let i = 0; i < posts.length; i++) {
      if (posts[i].pId === id) {
        if (posts[i].expanded === "") posts[i].expanded = id;
        else posts[i].expanded = "";
      }
    }
    setPosts(posts);
    console.info(posts);
  };

useEffect устанавливается для сообщений, которые следует вызывать всякий раз, когда происходит изменение состояния сообщений. Но его не вызывают.

  useEffect(() => {
    console.info("re render");
  }, [posts]);

Полный код:

export default function Posts({ userData }) {
  const [posts, setPosts] = useState([]);

  const getDate = (date) => {
    let seconds = date.seconds + date.nanoseconds / 1000000000;
    let newDate = new Date(seconds * 1000);
    return (
      newDate.getDate() +
      " " +
      newDate.toLocaleString("default", { month: "long" })
    );
  };

  const handleComment = (id) => {
    for (let i = 0; i < posts.length; i++) {
      if (posts[i].pId === id) {
        if (posts[i].expanded === "") posts[i].expanded = id;
        else posts[i].expanded = "";
      }
    }
    setPosts(posts);
    console.info(posts);
  };

  useEffect(() => {
    console.info("re render");
  }, [posts]);

  useEffect(() => {
    console.info("here");
    let parr = [];
    const unsub = database.posts
      .orderBy("createdAt", "desc")
      .onSnapshot((querySnapshot) => {
        parr = [];
        querySnapshot.forEach((doc) => {
          let data = { ...doc.data(), postId: doc.id, expanded: "" };
          parr.push(data);
        });
        setPosts(parr);
      });
    return unsub;
  }, []);

  return (
    <div style = {{ width: "55%" }}>
      {!posts || userData == null ? (
        <CircularProgress />
      ) : (
        <div className = "video-container">
          {posts && posts.map((post, index) => {
            console.info(post);
            return (
              <React.Fragment key = {index}>
                <Card sx = {{ maxWidth: 345 }} className = "card-class">
                  <CardHeader
                    avatar = {
                      <Avatar alt = "Remy Sharp" src = {userData.profileUrl} />
                    }
                    action = {
                      <IconButton aria-label = "settings">
                        <MoreVertIcon />
                      </IconButton>
                    }
                    title = {userData.fullname}
                    subheader = {getDate(post.createdAt)}
                  />
                  <Video src = {post.pURL} />
                  <CardActions disableSpacing>
                    <IconButton aria-label = "add to favorites">
                      <Like userData = {userData} postData = {post} />
                    </IconButton>
                    <IconButton
                      onClick = {() => handleComment(post.pId)}
                      aria-label = "comment"
                      aria-expanded = {post.expanded !== "" ? true : false}
                    >
                      <ChatBubbleIcon />
                    </IconButton>
                  </CardActions>
                  <Collapse
                    in = {post.expanded !== "" ? true : false}
                    timeout = "auto"
                    unmountOnExit
                  >
                    <CardContent>
                      <Typography paragraph>Method:</Typography>
                      <Typography paragraph>
                        Heat 1/2 cup of the broth in a pot until simmering, add
                        saffron and set aside for 10 minutes.
                      </Typography>
                      <Typography paragraph>
                        Heat oil in a (14- to 16-inch) paella pan or a large,
                        deep skillet over medium-high heat. Add chicken, shrimp
                        and chorizo, and cook, stirring occasionally until
                        lightly browned, 6 to 8 minutes. Transfer shrimp to a
                        large plate and set aside, leaving chicken and chorizo
                        in the pan. Add pimentón, bay leaves, garlic, tomatoes,
                        onion, salt and pepper, and cook, stirring often until
                        thickened and fragrant, about 10 minutes. Add saffron
                        broth and remaining 4 1/2 cups chicken broth; bring to a
                        boil.
                      </Typography>
                      <Typography paragraph>
                        Add rice and stir very gently to distribute. Top with
                        artichokes and peppers, and cook without stirring, until
                        most of the liquid is absorbed, 15 to 18 minutes. Reduce
                        heat to medium-low, add reserved shrimp and mussels,
                        tucking them down into the rice, and cook again without
                        stirring, until mussels have opened and rice is just
                        tender, 5 to 7 minutes more. (Discard any mussels that
                        don&apos;t open.)
                      </Typography>
                      <Typography>
                        Set aside off of the heat to let rest for 10 minutes,
                        and then serve.
                      </Typography>
                    </CardContent>
                  </Collapse>
                </Card>
              </React.Fragment>
            );
          })}
        </div>
      )}
    </div>
  );
}

Я также пытался использовать forEach, и здесь сообщения обновляются, а компонент повторно отображается, но сообщения не отображаются. Только CircularProgress движется.

  const handleComment = (id) => {
    let newPosts = [...posts]
    newPosts = posts.forEach((post) => {
      if (post.pId===id)
      {
        if (post.expanded== = "") post.expanded=id;
        else post.expanded = "";
      }
    })
    setPosts(newPosts);
    console.info(posts);
  };

Я попытался установить расширение до непустой строки, если это пустая строка, с помощью функции handleComment. Он работает нормально, но компонент не получает повторный рендеринг, в результате expanded остается пустой строкой.

А во втором случае forEach состояние сообщений обновляется, и компонент также перерисовывается, но движется только CircularProgress, а сообщения не отображаются.

Вы получаете какую-либо ошибку или предупреждение в своей консоли @Mohd Arsalan

Arun 08.02.2023 07:41
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
1
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я считаю, что он не обновляется, потому что вы изменяете массив posts вместо того, чтобы создавать новый. Что касается setPosts(), вы передали ему тот же массив, поэтому повторная визуализация не требуется (см. Обновление массивов в состоянии). Вы можете использовать map() для создания нового массива и одновременного выполнения логики.

const handleComment = (id) => {
  setPosts(posts.map(post => {
    if (post.pId === id) {
      return {
        ...post,
        expanded: post.expanded ? "" : id
      }
    } else {
      return post
    }
  }))
};

Я попытался создать новый массив, а затем обновить сообщения, используя forEach. В этом случае состояние сообщений обновляется, и также происходит повторный рендеринг, но я вижу только CircularProgress, а не сообщения. Смотрите последний код, который я добавил handleComment.

Mohd Arsalan 08.02.2023 08:15

@MohdArsalan В обновленном коде попробуйте заменить newPosts = posts.forEach на newPosts.forEach. В противном случае вы все еще мутируете posts и устанавливаете newPosts на undefined

Moarram 08.02.2023 08:40

Другие вопросы по теме