简体   繁体   中英

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>&#183;</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;

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>
    );
  });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM