【问题标题】:React API call in componentDidMount, and componentWillReceiveProps (order confusion)在 componentDidMount 和 componentWillReceiveProps 中 React API 调用(顺序混乱)
【发布时间】:2020-06-18 18:12:45
【问题描述】:

我对 React 和 Redux 还很陌生。我遇到了这个问题,当我刷新页面时,评分有时不显示(请参阅屏幕截图)。我认为这是因为有时来自 Redux 的用户会在 loadTeamsData 执行之前进入 componentWillReceiveProps,但我不知道为什么这会使评级不显示。 (另外,我觉得我的代码很垃圾……感谢任何批评者!)

Home.js

export class Home extends React.Component {

  state = {
    upVote: null,
    downVote: null,
    clickedTeam: "",
    teams: teams
  };

  // When component mounted, add in thumbUp & thumbDown properties to each team
  componentDidMount() {
    const { user } = this.props.auth;
    console.log("didmount");

    this.loadTeamsData();

    // Stores user voting info to state when coming from a different page
    if (user) {
      if (!(Object.entries(user).length === 0)) {
        console.log("user", user, user.upVote, user.downVote);
        this.setState({
          upVote: user.upVote,
          downVote: user.downVote
        });
      }
    }
  }

  // Loads teams thumbUp, thumbDown data to state
  loadTeamsData = () => {
    axios.get("/api/teams/").then(res => {
      console.log("data", res.data);
      this.setState({
        teams: this.state.teams.map(team => {
          res.data.map(vote => {
            if (vote.id === team.id) {
              team.thumbUp = vote.thumbUp;
              team.thumbDown = vote.thumbDown;
            }
            return vote;
          });
          return team;
        })
      });
    });
  };

  // When props from Redux come in, set the state
  UNSAFE_componentWillReceiveProps(nextProps) {
    const { user } = nextProps.auth;

    if (user !== this.props.auth.user && user) {
      console.log("willreceiveprops", `\n`, this.props.auth.user, user);
      this.setState({
        upVote: user.upVote,
        downVote: user.downVote
      });
    }
  }

  // Handle click on thumbs
  onClickHandler = (id, e) => {
    const { alert } = this.props;
    const up = e.target.classList.contains("up");

    if (this.props.auth.isAuthenticated) {
      if (up && this.state.upVote === "") {
        if (id === this.state.downVote) {
          alert.error("You cannot up vote and down vote the same team!");
        } else {
          this.props.update_up(id);
          this.setState(prevState => {
            return {
              teams: prevState.teams.map(team => {
                if (id === team.id) {
                  team.thumbUp = team.thumbUp + 1;
                  team.votedUpColor = { color: "#1E95E0" };
                }
                return team;
              }),
              clickedTeam: id,
              upVote: id
            };
          });
          alert.show(`You Up Voted ${id}`);
        }
      } else if (!up && this.state.downVote === "") {
        if (id === this.state.upVote) {
          alert.error("You cannot up vote and down vote the same team!");
        } else {
          this.props.update_down(id);
          this.setState(prevState => {
            return {
              teams: prevState.teams.map(team => {
                if (id === team.id) {
                  team.thumbDown = team.thumbDown + 1;
                  team.votedDownColor = { color: "#F8004C" };
                }
                return team;
              }),
              clickedTeam: id,
              downVote: id
            };
          });
          alert.show(`You Down Voted ${id}`);
        }
      } else {
        alert.show("You have already voted.");
      }
    } else {
      alert.show("Please log in first!");
      this.props.history.push(`/login`);
    }
  };

  // When user votes, update the db before updating the state
  UNSAFE_componentWillUpdate(newProps, newState) {
    newState.teams.map(team => {
      if (team.id === newState.clickedTeam) {
        axios.put(`/api/teams/${newState.clickedTeam}/`, {
          id: team.id,
          thumbUp: team.thumbUp,
          thumbDown: team.thumbDown
        });
      }
    });
  }

  render() {
    // Welcome header message when user logs in
    console.log("render", this.state.teams[0].thumbUp);
    const { isAuthenticated, user } = this.props.auth;
    const { upVote, downVote } = this.state;
    const welcome_header = (
      <div className="welcome-header">
        <h4 style={{ textAlign: "left" }} className="welcome-header-line">
          Welcome, {user && user.username}!
        </h4>
        <h4 style={{ textAlign: "left" }} className="welcome-header-line">
          <span>
            Your Vote:{" "}
            <i className="far fa-thumbs-up up" style={{ color: "#1E95E0" }}></i>
            <span style={{ textTransform: "capitalize" }}>{upVote}</span>
          </span>{" "}
          <span>
            <i
              className="far fa-thumbs-down down"
              style={{ color: "#F8004C" }}
            ></i>
            <span style={{ textTransform: "capitalize" }}>{downVote}</span>
          </span>
        </h4>
      </div>
    );

    return (
      <div className="home">
        <div className="home-container">
          {isAuthenticated && welcome_header}
          <h2>Who Is Your NBA Champion This Year?</h2>
          <Teams
            upVote={this.state.upVote}
            downVote={this.state.downVote}
            teams={this.state.teams}
            onClickHandler={this.onClickHandler}
          />
        </div>
      </div>
    );
  }
}

Home.propTypes = {
  update_up: PropTypes.func.isRequired,
  update_down: PropTypes.func.isRequired,
  auth: PropTypes.object.isRequired
};

const mapStateToProps = state => ({
  auth: state.auth
});

export default connect(mapStateToProps, { update_up, update_down })(
  withAlert()(withRouter(Home))
);

评分显示时

评分未显示时

我在渲染方法中记录this.state.teams[0]this.state.teams[0].thumbUp。 即使在第一次渲染期间,thumbUp 和 thumbDown 都显示在 this.state.teams[0] 中,但 this.state.teams[0].thumbUp 似乎未定义。

【问题讨论】:

  • 对象(正如它们旁边的 i 图标所说)在控制台中被延迟评估,这意味着它们在您展开对象时显示对象的值。这就是为什么原语是 undefined 而对象有值
  • 我明白了。谢谢你的解释!你知道是什么导致了这个错误吗?

标签: reactjs react-redux axios


【解决方案1】:

我碰巧解决了这个问题。问题实际上是在 Rating.js 文件中,很抱歉我没有发布该文件,因为我认为问题必须在 Home.js 中。

之前,在 Rating.js 文件中,我最初从 redux 引入了导致问题的用户(我相信在 Home.js 中 axios get 时它没有使 Rating 重新呈现通话发生在componentWillReceiveProps) 之后。

之后,我没有从 redux 引入用户,而是将用户作为 Home.js 的道具传递给 Rating.js。

即使它现在工作正常,我仍然不知道究竟是什么问题......如果有人能启发我,我将不胜感激!另外,请批评我的代码(即我可以改进的地方)!谢谢!

Rating.js(之前)

import React from "react";
import "./Rating.css";
import PropTypes from "prop-types";
import { connect } from "react-redux";

const Rating = props => {
  const { thumbUp, thumbDown, id, votedUpColor, votedDownColor } = props.team;
  const { upVote, downVote, onClickHandler } = props;
  const { user } = props.auth;

  let thumbUpColor =
    user && id === upVote ? { color: "#1E95E0" } : votedUpColor;
  let thumbDownColor =
    user && id === downVote ? { color: "#F8004C" } : votedDownColor;

  console.log(id, thumbUp, thumbDown);
  return (
    <div className="rating" key={id}>
      <button
        className="thumb-up up"
        style={thumbUpColor}
        onClick={e => onClickHandler(id, e)}
      >
        <i className="far fa-thumbs-up up"></i>
        <span style={{ userSelect: "none" }} className="up">
          {thumbUp}
        </span>
      </button>
      <button
        className="thumb-down down"
        style={thumbDownColor}
        onClick={e => onClickHandler(id, e)}
      >
        <i className="far fa-thumbs-down down"></i>
        <span style={{ userSelect: "none" }} className="down">
          {thumbDown}
        </span>
      </button>
    </div>
  );
};

Rating.propTypes = {
  team: PropTypes.object.isRequired,
  onClickHandler: PropTypes.func.isRequired,
  auth: PropTypes.object.isRequired
};

const mapStateToProps = state => ({
  auth: state.auth
});

export default connect(mapStateToProps)(Rating);

Rating.js(之后)

import React from "react";
import "./Rating.css";
import PropTypes from "prop-types";
// import { connect } from "react-redux";

const Rating = props => {
  const { thumbUp, thumbDown, id, votedUpColor, votedDownColor } = props.team;
  const { upVote, downVote, onClickHandler, user } = props;
  // const { user } = props.auth;

  let thumbUpColor =
    user && id === upVote ? { color: "#1E95E0" } : votedUpColor;
  let thumbDownColor =
    user && id === downVote ? { color: "#F8004C" } : votedDownColor;

  console.log(id, thumbUp, thumbDown);
  return (
    <div className="rating" key={id}>
      <button
        className="thumb-up up"
        style={thumbUpColor}
        onClick={e => onClickHandler(id, e)}
      >
        <i className="far fa-thumbs-up up"></i>
        <span style={{ userSelect: "none" }} className="up">
          {thumbUp}
        </span>
      </button>
      <button
        className="thumb-down down"
        style={thumbDownColor}
        onClick={e => onClickHandler(id, e)}
      >
        <i className="far fa-thumbs-down down"></i>
        <span style={{ userSelect: "none" }} className="down">
          {thumbDown}
        </span>
      </button>
    </div>
  );
};

Rating.propTypes = {
  team: PropTypes.object.isRequired,
  onClickHandler: PropTypes.func.isRequired
  // auth: PropTypes.object.isRequired
};

// const mapStateToProps = state => ({
//   auth: state.auth
// });

export default Rating;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-22
    • 1970-01-01
    • 2014-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-18
    相关资源
    最近更新 更多