首页 > 解决方案 > 执行操作后_id 丢失

问题描述

我目前正在创建我的第一个 MERN 应用程序,一切进展顺利,直到发生了一些事情,我将尝试解释,因为我需要帮助!

我正在做的是一个 facebook 克隆,您可以在其中发布一些内容,您可以删除您的帖子,您可以更新您的帖子,逻辑很简单,我调用 dispatch 将数据传递给操作,操作将数据传递给后端,后端返回一些东西给我,它保存在我的商店里,因为我正在使用 redux

问题是,当我有 2 个帖子,我想删除一个帖子,或者我想编辑它时,另一个帖子消失了,就像它丢失了它的 id 然后丢失了信息,然后我不能做除了重新加载页面之外,它总是会发生

这是它的样子,一切都很好

然后,在尝试编辑帖子后,第二个帖子丢失了信息,在控制台中,它说警告:列表中的每个孩子都应该有一个唯一的“key”道具,我已经给每个帖子 key={ _id},但帖子丢失了,我不知道如何

这是代码

Posts.js

import React, { useState } from "react";

import "./Posts.css";

import moment from "moment";

// Icons
import { BiDotsVertical, BiLike } from "react-icons/bi";
import { MdDeleteSweep } from "react-icons/md";
import { AiFillLike } from "react-icons/ai";
import { GrClose } from "react-icons/gr";

// Calling actions

import { deletePost,  } from "../actions/posts.js";

// Gettin The Data From Redux
import { useSelector, useDispatch } from "react-redux";

const Posts = ({ setCurrentId }) => {
  const [animation, setAnimation] = useState(false);
  const [modal, setModal] = useState(false);
  const [modalPost, setModalPost] = useState({});

  // Getting The Posts

  const posts = useSelector(state => state.posts);

  const dispatch = useDispatch();

  // Showing And Hiding Modal Window

  const ModalWindow = post => {
    setModalPost(post);
    setModal(true);
  };

  // Liking the post

  // const Like = id => {
  //   dispatch(giveLike(id));
  //   setAnimation(!animation);
  // };

  if (!posts.length) {
    return <div>Loading</div>;
  } else {
    return (
      <div className="Posts">
        {/* // Modal window for better look to the post */}

        {/* {modal && (
          <div className="modalWindow">
            <div className="container">
              <div className="container-image">
                <img src={modalPost.image} alt="" />
              </div>

              <div className="information">
                <div className="container-information">
                  <div className="data-header">
                    <h2>
                      User <br />{" "}
                      <span style={{ fontWeight: "400" }}>
                        {moment(modalPost.createdAt).fromNow()}
                      </span>
                    </h2>
                    <span className="data-icon" onClick={() => setModal(false)}>
                      <GrClose />
                    </span>
                  </div>

                  <div className="message">
                    <h2>{modalPost.title}</h2>
                    <p>{modalPost.message}</p>
                  </div>
                </div>
              </div>
            </div>
          </div>
        )} */}

        {/*  */}

        {posts.map(post => {
          const { _id, title, message, image, createdAt, likes } = post;
          return (
            <div className="Posts-container" key={_id}>
              <div className="Fit">
                <div className="Fit-stuff">
                  <h2 className="Fit-stuff_title">
                    User <br />{" "}
                    <span style={{ fontWeight: "400" }}>
                      {moment(createdAt).fromNow()}
                    </span>
                  </h2>
                  <a
                    className="Fit-stuff_edit"
                    href="#form"
                    onClick={() => setCurrentId(_id)}
                  >
                    <BiDotsVertical />
                  </a>
                </div>

                <div className="Fit-data">
                  <h2 className="Fit-data_title">{title}</h2>
                  <p className="Fit-data_message">{message}</p>
                  {image ? (
                    <div className="Fit-img">
                      <img
                        onClick={() => ModalWindow(post)}
                        src={image}
                        alt=""
                      />
                    </div>
                  ) : (
                    <div></div>
                  )}
                </div>

                <div className="Fit-shit">
                  <span>
                    {animation ? (
                      <AiFillLike className="fullLightBlue" />
                    ) : (
                      <BiLike />
                    )}
                    {likes}
                  </span>
                  <span onClick={() => dispatch(deletePost(_id))}>
                    <MdDeleteSweep />
                  </span>
                </div>
              </div>
            </div>
          );
        })}
      </div>
    );
  }
};

export default Posts;

我调用更新和创建帖子的表单

import React, { useState, useEffect } from "react";

import Filebase from "react-file-base64";

// For the actions
import { useDispatch, useSelector } from "react-redux";
import { createPost, updatePost } from "../actions/posts.js";
import {
  Wrapper,
  FormContainer,
  Data,
  DataInput,
  SecondDataInput,
  FormContainerImg,
  FormContainerButtons,
  Buttons
} from "./FormStyled.js";

const Form = ({ currentId, setCurrentId }) => {
  const [formData, setFormData] = useState({
    title: "",
    message: "",
    image: ""
  });

  const specificPost = useSelector(state =>
    currentId ? state.posts.find(p => p._id === currentId) : null
  );

  // Sending The Data And Editing The data

  const dispatch = useDispatch();

  useEffect(() => {
    if (specificPost) setFormData(specificPost);
  }, [specificPost]);

  // Clear Inputs

  const clear = () => {
    setCurrentId(0);
    setFormData({ title: "", message: "", image: "" });
  };

  const handleSubmit = async e => {
    e.preventDefault();
    if (currentId === 0) {
      dispatch(createPost(formData));
      clear();
    } else {
      dispatch(updatePost(currentId, formData));
      clear();
    }
  };

  return (
    <Wrapper>
      <FormContainer onSubmit={handleSubmit}>
        <Data>
          <DataInput
            name="title"
            maxLength="50"
            placeholder="Title"
            type="text"
            value={formData.title}
            onChange={e => setFormData({ ...formData, title: e.target.value })}
          />
          <SecondDataInput
            name="message"
            placeholder="Message"
            maxLength="300"
            value={formData.message}
            required
            onChange={e =>
              setFormData({ ...formData, message: e.target.value })
            }
          />
          <FormContainerImg>
            <Filebase
              required
              type="file"
              multiple={false}
              onDone={({ base64 }) =>
                setFormData({ ...formData, image: base64 })
              }
            />
          </FormContainerImg>
          <FormContainerButtons>
            <Buttons type="submit" create>
              {specificPost ? "Edit" : "Create"}
            </Buttons>
            <Buttons onClick={clear} clear>
              Clear
            </Buttons>
          </FormContainerButtons>
        </Data>
      </FormContainer>
    </Wrapper>
  );
};

export default Form;

我的行动

import {
  GETPOSTS,
  CREATEPOST,
  DELETEPOST,
  UPDATEPOST,
  LIKEPOST
} from "../actionTypes/posts.js";

import * as api from "../api/posts.js";

export const getPosts = () => async dispatch => {
  try {
    const { data } = await api.getPosts();

    dispatch({ type: GETPOSTS, payload: data });
  } catch (error) {
    console.log(error);
  }
};

export const createPost = newPost => async dispatch => {
  try {
    const { data } = await api.createPost(newPost);
    dispatch({ type: CREATEPOST, payload: data });
  } catch (error) {
    console.log(error);
  }
};

export const updatePost = (id, updatePost) => async dispatch => {
  try {
    const { data } = await api.updatePost(id, updatePost);

    dispatch({ type: UPDATEPOST, payload: data });
  } catch (error) {
    console.log(error);
  }
};

export const deletePost = id => async dispatch => {
  try {
    await api.deletePost(id);

    dispatch({ type: DELETEPOST, payload: id });
  } catch (error) {
    console.log(error);
  }
};

还原部分

import {
  GETPOSTS,
  CREATEPOST,
  DELETEPOST,
  UPDATEPOST,
  LIKEPOST
} from "../actionTypes/posts.js";

const postData = (posts = [], action) => {
  switch (action.type) {
    case GETPOSTS:
      return action.payload;

    case CREATEPOST:
      return [...posts, action.payload];

    case UPDATEPOST:
      return posts.map(post =>
        action.payload._id === post._id ? action.payload : posts
      );

    case DELETEPOST:
      return posts.filter(post => post._id !== action.payload);

    default:
      return posts;
  }
};

export default postData;

我在后端的控制器

import mongoose from "mongoose";
import infoPost from "../models/posts.js";

// Getting All The Posts

export const getPosts = async (req, res) => {
  try {
    const Posts = await infoPost.find();

    res.status(200).json(Posts);
  } catch (error) {
    res.status(404).json({ message: error.message });
    console.log(error);
  }
};

// Creating A Post

export const createPost = async (req, res) => {
  const { title, message, image } = req.body;

  const newPost = new infoPost({ title, message, image });
  try {
    await newPost.save();
    res.status(201).json(newPost);
  } catch (error) {
    res.status(409).json({ message: error.message });
    console.log(error);
  }
};

// Update A Post

export const updatePost = async (req, res) => {
  const { id } = req.params;

  const { title, message, image } = req.body;

  if (!mongoose.Types.ObjectId.isValid(id))
    return res.status(404).send(`No Post With Id Of ${id}`);

  const updatedPost = { title, message, image, _id: id };

  await infoPost.findByIdAndUpdate(id, updatedPost, { new: true });

  res.json(updatedPost);
};

// Deleting A Post

export const deletePost = async (req, res) => {
  const { id } = req.params;

  if (!mongoose.Types.ObjectId.isValid(id))
    return res
      .status(404)
      .send(`We Couldnt Found The Post With Id Of ${id} To Delete`);

  await infoPost.findByIdAndRemove(id);

  res.json(`Post With Id Of ${id} Deleted Succesfully`);
};

// Liking A Post

export const likePost = async (req, res) => {
  const { id } = req.params;

  if (!mongoose.Types.ObjectId.isValid(id))
    return res.status(404).send(`No post with id: ${id}`);

  const post = await infoPost.findById(id);

  const updatedPost = await infoPost.findByIdAndUpdate(
    id,
    { likeCount: post.likeCount + 1 },
    { new: true }
  );

  res.json(updatedPost);
};

尽管我已经尝试解决这个问题将近 3.5 个小时,但我认为问题可能出在我的 Posts.js 部分,如果你能帮助我,你就是最棒的!

标签: node.jsreactjsexpressreact-redux

解决方案


推荐阅读