在Redux中更改状态后,组件未重新呈现

时间:2020-04-01 06:06:32

标签: reactjs express redux react-redux redux-thunk

我正在尝试删除帖子,但好像我必须每次刷新页面。当我查看Chrome中的React devtools时,商店也在刷新后更新。我需要了解其背后的原因。

因此,我在UserPosts之类的路线上有一个www.abc.com/profile/jimmy/posts组件。此页面以卡片形式包含用户的帖子。这些也具有删除按钮。

UserPosts.js

import React, { Component } from "react"
import { getUserPosts, getCurrentUser } from "../actions/userActions"
import { connect } from "react-redux"
import Cards from "./Cards"

class UserPosts extends Component {
  componentDidMount() {
    const authToken = localStorage.getItem("authToken")
    if (authToken) {
      this.props.dispatch(getCurrentUser(authToken))
      if (this.props && this.props.userId) {
        this.props.dispatch(getUserPosts(this.props.userId))
      } else {
        return null
      }
    }
  }


  render() {
    const { isFetchingUserPosts, userPosts } = this.props
    console.log(userPosts)
    return isFetchingUserPosts ? (
      <p>Fetching....</p>
    ) : (
      <div>
        {userPosts &&
          userPosts.map(post => {
            return <Cards key={post._id} post={post} />
          })}
      </div>
    )
  }
}

const mapStateToPros = state => {
  return {
    isFetchingUserPosts: state.userPosts.isFetchingUserPosts,
    userPosts: state.userPosts.userPosts,
    userId: state.auth.user._id
  }
}

export default connect(mapStateToPros)(UserPosts)

Cards.js

import React, { Component } from "react"
import { connect } from "react-redux"
import { deletePost } from "../actions/userActions"

class Cards extends Component {

  handleDelete = (_id) => {
    this.props.dispatch(deletePost(_id))
  }

  render() {
    const { _id, title, description } = this.props.post
    return (
      <div className="card">  
        <div className="card-content">
          <div className="media">
            <div className="media-left">
              <figure className="image is-48x48">
                <img
                  src="https://bulma.io/images/placeholders/96x96.png"
                  alt="Placeholder image"
                />
              </figure>
            </div>
            <div className="media-content" style={{border: "1px grey"}}>
              <p className="title is-5">{title}</p>
              <p className="content">{description}</p>
              <button className="button is-success">Edit</button>
              <button onClick={() => {this.handleDelete(_id)}} className="button is-success">Delete</button>
            </div>
          </div>
        </div>
      </div>
    )
  }
}

const mapStateToProps = () => {
  return {
    nothing: "nothing"
  }
}

export default connect(mapStateToProps)(Cards)

删除发布操作

export const deletePost = (id) => {
    return async (dispatch) => {
      dispatch({ type: "DELETING_POST_START" })
      try {
        const deletedPost = await axios.delete(`http://localhost:3000/api/v1/posts/${id}/delete`)
        dispatch({
          type: "DELETING_POST_SUCCESS",
          data: deletedPost
        })
      } catch(error) {
        dispatch({
          type: "DELETING_POST_FAILURE",
          data: { error: "Something went wrong" }
        })
      }
    }
  }

userPosts reducer

const initialState = {
  isFetchingUserPosts: null,
  isFetchedUserPosts: null,
  userPosts: [],
  fetchingUserPostsError: null
}

const userPosts = (state = initialState, action) => {
  switch (action.type) {
    case "FETCHING_USER_POSTS_START":
      return {
        ...state,
        isFetchingUserPosts: true,
        fetchingUserPostsError: null
      }
    case "FETCHING_USER_POSTS_SUCCESS":
      return {
        ...state,
        isFetchingUserPosts: false,
        isFetchedUserPosts: true,
        userPosts: action.data,
        fetchingUserPostsError: null
      }
    case "FETCHING_USER_POSTS_ERROR":
      return {
        ...state,
        isFetchingUserPosts: false,
        isFetchedUserPosts: false,
        fetchingUserPostsError: action.data.error
      }
    default:
      return state
  }
}

export default userPosts

后减速器

const initialState = {
  isAddingPost: false,
  postError: null,
  post: {},
  isFetchingPosts: null,
  isFetchedPosts: null,
  fetchingPostsError: null,
  isDeletingPost: false,
  isDeletedPost: false,
  deletingError: null,
  postList: []
}

const post = (state = initialState, action) => {
  switch (action.type) {
    case "ADD_POST_STARTS":
      return { ...state, isAddingPost: true, postError: null }
    case "ADD_POST_SUCCESS":
      return {
        ...state,
        isAddingPost: false,
        postError: null,
        post: action.data
      }
    case "ADD_POST_ERROR":
      return {
        ...state,
        isAddingPost: false,
        postError: action.data.error,
        post: {}
      }
    case "FETCHING_POSTS_START":
      return {
        ...state,
        isFetchingPosts: true,
        isFetchedPosts: false,
        fetchingPostsError: null
      }
    case "FETCHING_POSTS_SUCCESS":
      return {
        ...state,
        isFetchingPosts: false,
        isFetchedPosts: true,
        fetchingPostsError: null,
        postList: action.data.posts
      }
    case "FETCHING_POSTS_ERROR":
      return {
        ...state,
        isFetchingPosts: false,
        isFetchedPosts: false,
        fetchingPostsError: action.data.error
      }
    case "DELETING_POST_START":
      return {
        ...state,
        isDeletingPost: true,
        deletingError: null
      }
    case "DELETING_POST_SUCCESS":
      const filteredPostList = state.postList.filter(
        post => post._id !== action.data._id
      )
      return {
        ...state,
        isDeletingPost: false,
        isDeletedPost: true,
        postList: filteredPostList,
        deletingError: null
      }
    case "DELETING_POST_ERROR":
      return {
        ...state,
        isDeletingPost: false,
        deletingError: action.data.error
      }
    default:
      return state
  }
}

export default post

我只需要知道如何解决此问题以及为什么它没有按预期发生。谢谢。

编辑:我也有一个deletePost控制器。是造成问题的原因吗?

router.delete("/:id/delete", postsController.deletePost)

 deletePost: async (req, res, next) => {
    try {
      const post = await Post.findByIdAndDelete(req.params.id)
      if (!post) {
        return res.status(200).json({ error: "No post found"})
      }
      return res.status(200).json({ post })
    } catch(error) {
        return res.json({ error })
    }
  }

2 个答案:

答案 0 :(得分:0)

请确保您在删除项目时API返回ID,如果确实如此,请确保它在_id中返回。

这里有一些重构,所以看起来更易读:

UserPosts.js

import React, { Component } from "react";
import { getUserPosts, getCurrentUser } from "../actions/userActions";
import { connect } from "react-redux";
import Cards from "./Cards";

class UserPosts extends Component {
  componentDidMount() {
    const authToken = localStorage.getItem("authToken");
    const { getCurrentUser, getUserPosts, userId } = this.props;

    if (authToken) {
      getCurrentUser(authToken);
      userId ? getUserPosts(userId) : null;
    }
  }

  render() {
    const { isFetchingUserPosts, userPosts } = this.props;

    return isFetchingUserPosts ? (
      <p>Fetching....</p>
    ) : (
      <div>
        {userPosts &&
          userPosts.map((post) => {
            return <Cards key={post._id} post={post} />;
          })}
      </div>
    );
  }
}

const mapStateToPros = (state) => {
  return {
    isFetchingUserPosts: state.userPosts.isFetchingUserPosts,
    userPosts: state.userPosts.userPosts,
    userId: state.auth.user._id,
  };
};

const mapDispatchToProps = (dispatch) => {
  return {
    getCurrentUser: (authToken) => {
      dispatch(getCurrentUser(authToken));
    },
    getUserPosts: (userId) => {
      dispatch(getUserPosts(userId));
    },
  };
};

export default connect(mapStateToPros)(UserPosts);

Cards.js

class Cards extends Component {
  handleDelete = (id) => {
    this.props.deletePost(id);
  };

  render() {
    const { _id, title, description } = this.props.post;
    return (
      <div className="card">
        <div className="card-content">
          <div className="media">
            <div className="media-left">
              <figure className="image is-48x48">
                <img
                  src="https://bulma.io/images/placeholders/96x96.png"
                  alt="Placeholder image"
                />
              </figure>
            </div>
            <div className="media-content" style={{ border: "1px grey" }}>
              <p className="title is-5">{title}</p>
              <p className="content">{description}</p>
              <button className="button is-success">Edit</button>
              <button
                onClick={() => {
                  this.handleDelete(_id);
                }}
                className="button is-success"
              >
                Delete
              </button>
            </div>
          </div>
        </div>
      </div>
    );
  }
}

const mapStateToProps = () => {
  return {
    nothing: "nothing",
  };
};

const mapDispatchToProps = (dispatch) => {
  return {
    deletePost: (id) => {
      dispatch(deletePost(id));
    },
  };
};

export default connect(mapStateToProps)(Cards);

deletePostAction

export const deletePost = (id) => {
  return async (dispatch) => {
    dispatch({ type: "DELETING_POST_START" });
    axios
      .delete(`http://localhost:3000/api/v1/posts/${id}/delete`)
      .then(({ data }) => {
        // as the post is being returned in data.post
        // get that object and pass to data inside dispatch
        const { post } = data;
        dispatch({
          type: "DELETING_POST_SUCCESS",
          data: post,
        });
      })
      .catch((error) => {
        dispatch({
          type: "DELETING_POST_FAILURE",
          data: { error: "Something went wrong" },
        });
      });
  };
};

答案 1 :(得分:0)

导出没有mapdispatchtoprops,请尝试类似的操作。对Post组件也要执行相同的操作

import React, { Component } from "react"
import { connect } from "react-redux"
import { deletePost } from "../actions/userActions"

class Cards extends Component {

  handleDelete = (_id) => {
    this.props.deletePostAction(_id)
  }

  render() {
    const { _id, title, description } = this.props.post
    return (
      <div className="card">  
        <div className="card-content">
          <div className="media">
            <div className="media-left">
              <figure className="image is-48x48">
                <img
                  src="https://bulma.io/images/placeholders/96x96.png"
                  alt="Placeholder image"
                />
              </figure>
            </div>
            <div className="media-content" style={{border: "1px grey"}}>
              <p className="title is-5">{title}</p>
              <p className="content">{description}</p>
              <button className="button is-success">Edit</button>
              <button onClick={() => {this.handleDelete(_id)}} className="button is-success">Delete</button>
            </div>
          </div>
        </div>
      </div>
    )
  }
}

const mapStateToProps = () => {
  return {
    nothing: "nothing"
  }
}
const mapDispatchToProps = dispatch => ({
    deletePostAction: () => dispatch(deletePost)
});
export default connect(mapStateToProps,mapDispatchToProps)(Cards)