Я использую карту 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'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, а сообщения не отображаются.
Я считаю, что он не обновляется, потому что вы изменяете массив 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
.
@MohdArsalan В обновленном коде попробуйте заменить newPosts = posts.forEach
на newPosts.forEach
. В противном случае вы все еще мутируете posts
и устанавливаете newPosts
на undefined
Вы получаете какую-либо ошибку или предупреждение в своей консоли @Mohd Arsalan