正在调用但未命中的动作

Action being callled but not hitting

我正在使用 MERN 堆栈和 redux,我创建了一个 findOneAndUpdate api 并在 Postman 上对其进行了测试。一切正常,但我无法在我的网站上运行。它从未真正触发 updateSubject 操作。我是否错误地传递了数据?有人知道我错过了什么吗?

行动

export const updateSubject = (id, rate, noOfVotes, rating) => (dispatch) => {
  console.log("updateSubject hitting");
  fetch(`/api/subjects/Subject/${id}/${rate}/${noOfVotes}/${rating}`)
    .then((res) => res.json())
    .then((subject) =>
      dispatch({
        type: UPDATE_SUBJECT,
        subjects: subject,
      })
    );
};

api

// update subject
subjectRouter.put("/subject/:_id/:rate/:noOfVotes/:rating", (req, res) => {
  Subject.findOneAndUpdate(
    { _id: req.params._id },
    {
      rating: Number(req.params.rating) + Number(req.params.rate),
      noOfVotes: Number(req.params.noOfVotes) + 1,
    },
    {
      new: true,
      useFindAndModify: false,
    }
  )
    .then((subjects) => res.json(subjects))
    .catch((err) => console.log(err));
});

组件

import React, { Component } from "react";
import PropTypes from "prop-types";
import GoogleSearch from "./GoogleSearch";
import { connect } from "react-redux";
import { fetchSubjects } from "../../actions/subject";
import { fetchComments } from "../../actions/comment";
import { updateSubject } from "../../actions/subject";

class Subject extends Component {
  // on loading the subjects and comments
  // are fetched from the database
  componentDidMount() {
    this.props.fetchSubjects();
    this.props.fetchComments();
  }

  constructor(props) {
    super(props);
    this.state = {
      // set inital state for subjects description
      // and summary to invisible
      viewDesription: -1,
      viewSummary: -1,
      comments: [],
    };
  }

  componentWillReceiveProps(nextProps) {
    // new subject and comments are added to the top
    if (nextProps.newPost) {
      this.props.subjects.unshift(nextProps.newPost);
    }
    if (nextProps.newPost) {
      this.props.comments.unshift(nextProps.newPost);
    }
  }

  clickHandler = (id) => {
    // when a subject title is clicked pass in its id
    // and make the desciption visible
    const { viewDescription } = this.state;
    this.setState({ viewDescription: viewDescription === id ? -1 : id });
    // add relevant comments to the state
    var i;
    var temp = [];
    for (i = 0; i < this.props.comments.length; i++) {
      if (this.props.comments[i].subject === id) {
        temp.unshift(this.props.comments[i]);
      }
    }
    this.setState({
      comments: temp,
    });
    // save the subject id to local storage
    // this is done incase a new comment is added
    // then the subject associated  with it can be retrieved
    // and added as a property of that comment
    localStorage.setItem("passedSubject", id);
  };

  // hovering on and off subjects toggles the visibility of the summary
  hoverHandler = (id) => {
    this.setState({ viewSummary: id });
  };
  hoverOffHandler = () => {
    this.setState({ viewSummary: -1 });
  };

  rateHandler = (id, rate) => {
    var currRate;
    var currVotes;
    var i;
    for (i = 0; i < this.props.subjects.length; i++) {
      if (this.props.subjects[i]._id === id) {
        currRate = this.props.subjects[i].rating;
        currVotes = this.props.subjects[i].noOfVotes;
      }
    }
    updateSubject(id, rate, currVotes, currRate);
    console.log(id, rate, currVotes, currRate);
  };

  findAuthor(id) {
    // search users for id return name
  }

  render() {
    const subjectItems = this.props.subjects.map((subject) => {
      // if the state equals the id set to visible if not set to invisible
      var view = this.state.viewDescription === subject._id ? "" : "none";
      var hover = this.state.viewSummary === subject._id ? "" : "none";
      var comments = this.state.comments;
      return (
        <div key={subject._id}>
          <div
            className="subjectTitle"
            onClick={() => this.clickHandler(subject._id)}
            onMouseEnter={() => this.hoverHandler(subject._id)}
            onMouseLeave={() => this.hoverOffHandler()}
          >
            <p className="title">{subject.title}</p>
            <p className="rate">
              Rate this subject:
              <button onClick={() => this.rateHandler(subject._id, 1)}>
                1
              </button>
              <button onClick={() => this.rateHandler(subject._id, 2)}>
                2
              </button>
              <button onClick={() => this.rateHandler(subject._id, 3)}>
                3
              </button>
              <button onClick={() => this.rateHandler(subject._id, 4)}>
                4
              </button>
              <button onClick={() => this.rateHandler(subject._id, 5)}>
                5
              </button>
            </p>
            <p className="rating">
              Rating: {(subject.rating / subject.noOfVotes).toFixed(1)}/5
            </p>
            <p className="summary" style={{ display: hover }}>
              {subject.summary}
            </p>
          </div>

          <div className="subjectBody " style={{ display: view }}>
            <div className="subjectAuthor">
              <p className="author" style={{ fontWeight: "bold" }}>
                Subject created by: {subject.author} on {subject.date}
              </p>
            </div>

            <div className="subjectDescription">
              <p className="description">{subject.description}</p>
            </div>

            <div className="subjectLinks">Links:</div>

            <div className="subjectComments">
              <p style={{ fontWeight: "bold" }}>Comments:</p>
              {comments.map((comment, i) => {
                return (
                  <div key={i} className="singleComment">
                    <p>
                      {comment.title}
                      <br />
                      {comment.comment}
                      <br />
                      Comment by : {comment.author}
                    </p>
                  </div>
                );
              })}
              <a href="/addcomment">
                <div className="buttonAddComment">ADD COMMENT</div>
              </a>
            </div>
          </div>
        </div>
      );
    });

    return (
      <div id="Subject">
        <GoogleSearch />
        {subjectItems}
      </div>
    );
  }
}

Subject.propTypes = {
  fetchSubjects: PropTypes.func.isRequired,
  fetchComments: PropTypes.func.isRequired,
  subjects: PropTypes.array.isRequired,
  comments: PropTypes.array.isRequired,
  newPost: PropTypes.object,
};

const mapStateToProps = (state) => ({
  subjects: state.subjects.items,
  newSubject: state.subjects.item,
  comments: state.comments.items,
  newComment: state.comments.item,
});

// export default Subject;
export default connect(mapStateToProps, { fetchSubjects, fetchComments })(
  Subject,
  Comment
);

您没有将 updateSubject 附加到组件本身,目前您只有 fetchSubjectsfetchComments

因此,您需要像这样更改连接函数:

export default connect(mapStateToProps, { fetchSubjects, fetchComments, updateSubject })(
  Subject,
  Comment
);

然后你的调用函数可以这样改变:

rateHandler = (id, rate) => {
  const subject = this.props.subjects.find( subject => subject._id === id);
  // when no subject was found, the updateSubject won't be called
  subject && this.props.updateSubject( id, rate, subject.noOfVotes, subject.rating );
};

这也意味着您应该像这样更新您的道具类型:

Subject.propTypes = {
  fetchSubjects: PropTypes.func.isRequired,
  fetchComments: PropTypes.func.isRequired,
  updateSubject: PropTypes.func.isRequired,
  subjects: PropTypes.array.isRequired,
  comments: PropTypes.array.isRequired,
  newPost: PropTypes.object,
};

正如您在评论中提到的,您正在使用 put 端点,因此您可能应该将 updateSubject 方法更新为以下

export const updateSubject = (id, rate, noOfVotes, rating) => (dispatch) => {
  console.log("updateSubject hitting");
  fetch(`/api/subjects/Subject/${id}/${rate}/${noOfVotes}/${rating}`, { method: 'PUT' })
    .then((res) => res.json())
    .then((subject) =>
      dispatch({
        type: UPDATE_SUBJECT,
        subjects: subject,
      })
    );
};