'Removes only the last list item bug React
So I have a list of items being generated and for some reason whenever I try to remove one (the handleDelete callback onClick function), it always removes the last item. I added keys to each item so I'm not sure why it's not working. I would appreciate any insight!
Places to look:
handleDelete()
Keys to Box element of each list item
const data = [
{
id: "0a",
name: "Jbone",
tag: "@jbone",
timePosted: "5 min",
content:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Etiam erat velit scelerisque in dictum non consectetur. Massa tincidunt dui ut ornare lectus sit.",
},
{
id: "1b",
name: "T",
tag: "@t",
timePosted: "5 min",
content:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Etiam erat velit scelerisque in dictum non consectetur. Massa tincidunt dui ut ornare lectus sit.",
},
{
id: "2c",
name: "W",
tag: "@w",
timePosted: "5 min",
content:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Etiam erat velit scelerisque in dictum non consectetur. Massa tincidunt dui ut ornare lectus sit.",
},
{
id: "3d",
name: "X",
tag: "@x",
timePosted: "5 min",
content:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Etiam erat velit scelerisque in dictum non consectetur. Massa tincidunt dui ut ornare lectus sit.",
},
];
const HeaderComponent = ({ name, tag, time }) => {
return (
<>
<strong>{name}</strong>{" "}
<Typography component="span" variant="body2">
{tag} <span>·</span> {time}
</Typography>
</>
);
};
const AlignItemsList = ({ feed, setFeed }) => {
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const handleDelete = (id) => {
console.log(id);
// setFeed(prevFeed => {
// const feed = prevFeed.filter(post => post.key !== key)
// return feed;
// })
setAnchorEl(null);
};
const open = Boolean(anchorEl);
const id = open ? "simple-popover" : undefined;
return feed.map((post) => {
// console.log(post.key)
return (
<Box key={post.id}>
<ListItem
alignItems="flex-start"
secondaryAction={
<ListItemText
primary={
<IconButton onClick={handleClick}>
<MoreHorizIcon />
</IconButton>
}
/>
}
>
<ListItemAvatar>
<Avatar alt="Remy Sharp" src="/static/images/avatar/1.jpg" />
</ListItemAvatar>
<ListItemText
primary={
<HeaderComponent
name={post.name}
tag={post.tag}
time={post.timePosted}
/>
}
secondary={
<React.Fragment>
<Typography
sx={{ display: "inline" }}
component="span"
variant="body2"
color="text.primary"
>
{post.content}
</Typography>
</React.Fragment>
}
/>
<Popover
id={id}
open={open}
anchorEl={anchorEl}
onClose={handleClose}
anchorOrigin={{
vertical: "bottom",
horizontal: "left",
}}
>
<Typography sx={{ p: 2 }}>
<Button onClick={() => handleDelete(post.id)}>Delete</Button>
</Typography>
</Popover>
</ListItem>
<Divider variant="inset" component="li" />
</Box>
);
});
};
const PostFeed: React.FC = () => {
const [inputStr, setInputStr] = useState("");
const [feed, setFeed] = useState<any>(data);
const [showPicker, setShowPicker] = useState(false);
const onEmojiClick = (event, emojiObject) => {
setInputStr((prevInput) => prevInput + emojiObject.emoji);
setShowPicker(false);
};
const onPostClick = () => {
if (inputStr != "") {
setFeed((prevFeed) => {
return [
...prevFeed,
{
id: `${prevFeed.length}` + "xz",
name: "Jasper",
tag: "@friendlyghost",
timePosted: "10 min",
content: inputStr,
},
];
});
setInputStr("");
}
};
const handleKeypress = (e) => {
//it triggers by pressing the enter key
if (e.key === "Enter") {
onPostClick();
}
};
return (
<>
<Paper style={{ height: "12em", paddingTop: "4em" }}>
<Container>
<Box sx={{ display: "flex", marginBottom: "2em" }}>
<Avatar style={{ marginRight: "1em" }} />
<input
style={{ outline: "none", border: "none", width: "100%" }}
placeholder="add a post here..."
value={inputStr}
onChange={(e) => setInputStr(e.target.value)}
onKeyPress={(e) => handleKeypress(e)}
/>
</Box>
<Divider />
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
marginTop: ".5em",
}}
>
<SentimentSatisfiedAltOutlinedIcon
onClick={() => setShowPicker((val) => !val)}
/>
<Button
variant="contained"
onClick={() => onPostClick()}
disabled={inputStr === ""}
>
Post
</Button>
</div>
{showPicker && (
<Picker
pickerStyle={{ width: "100%" }}
onEmojiClick={onEmojiClick}
/>
)}
<Box sx={{ marginTop: "6em" }}>
<List sx={{ bgcolor: "background.paper" }}>
<AlignItemsList feed={feed} setFeed={setFeed} />
</List>
</Box>
</Container>
</Paper>
</>
);
};
export default PostFeed;
Solution 1:[1]
Try this?
const handleDelete = (key) => {
console.log(key);
setFeed(prevFeed => {
const feed = prevFeed.filter(post => post.key !== key)
return feed;
})
setAnchorEl(null);
};
but better than sending setFeed
fn it's make callback like this onDelete={handleDelete}
<AlignItemsList feed={feed} onDelete={handleDelete} />
and of course move code for delete from AlignItemsList
to parent.
EDIT part of code:
return feed.map((post) => {
const { id, content, name, tag, timePosted } = post;
return (
<Box key={id}>
<ListItem
alignItems="flex-start"
secondaryAction={
<ListItemText
primary={
<IconButton onClick={handleClick}>
<MoreHorizIcon />
</IconButton>
}
/>
}
>
<ListItemAvatar>
<Avatar alt="Remy Sharp" src="/static/images/avatar/1.jpg" />
</ListItemAvatar>
<ListItemText
primary={
<HeaderComponent
name={name}
tag={tag}
time={timePosted}
/>
}
secondary={
<React.Fragment>
<Typography
sx={{ display: "inline" }}
component="span"
variant="body2"
color="text.primary"
>
{content}
</Typography>
</React.Fragment>
}
/>
<Popover
id={id}
open={open}
anchorEl={anchorEl}
onClose={handleClose}
anchorOrigin={{
vertical: "bottom",
horizontal: "left",
}}
>
<Typography sx={{ p: 2 }}>
<Button onClick={() => handleDelete(id)}>Delete</Button>
</Typography>
</Popover>
</ListItem>
<Divider variant="inset" component="li" />
</Box>
);
});
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |