【问题标题】:Removes only the last list item bug React仅删除最后一个列表项错误 React
【发布时间】:2022-01-27 02:33:17
【问题描述】:

所以我有一个正在生成的项目列表,并且由于某种原因,每当我尝试删除一个(handleDelete 回调 onClick 函数)时,它总是删除最后一个项目。我为每个项目添加了密钥,所以我不确定它为什么不起作用。如果有任何见解,我将不胜感激!

看的地方:

handleDelete()

每个列表项的 Box 元素的键

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;

【问题讨论】:

  • post.key !== key 也许你的意思是post.id !== id
  • 似乎是一个错字,您的数据没有key 属性。 prevFeed.filter(post =&gt; post.key !== key) 应该是 prevFeed.filter(post =&gt; post.id !== id)。投票结束为“不可复制或由错字引起。干杯。
  • 所以该属性曾经被称为 key 所以这就是它存在的原因。我注释掉了代码,因为我想查看是否在 handleDelete 回调中发送了正确的帖子 ID,但事实并非如此。无论我点击什么帖子,我都会不断获得最后一个帖子 ID。
  • 您能否更新您的问题以包含您遇到问题的实际代码?如果可以,请尝试创建一个 running 代码框演示,重现我们可以现场检查和调试的问题?

标签: javascript reactjs material-ui next.js


【解决方案1】:

试试这个?

  const handleDelete = (key) => {
    console.log(key);
    setFeed(prevFeed => {
      const feed = prevFeed.filter(post => post.key !== key)
      return feed;
    })
    setAnchorEl(null);
  };

但比发送setFeed fn 更好,它会像这样onDelete={handleDelete} 进行回调

<AlignItemsList feed={feed} onDelete={handleDelete} />

当然还有将删除代码从AlignItemsList 移到父级。

编辑 部分代码:

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

【讨论】:

  • 所以 id 属性曾经被称为 key 所以我现在把它注释掉了。当我在 handleDelete 回调函数中控制台记录 id 时,问题仍然存在。我不断得到上一篇文章的 id。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-12
相关资源
最近更新 更多