Реагировать на вызов API в componentDidMount и componentWillReceiveProps (путаница в порядке) - PullRequest
0 голосов
/ 06 марта 2020

Я довольно новичок в React и Redux. У меня возникла проблема, когда рейтинги иногда не отображаются при обновлении sh страницы (см. Скриншот). Я думаю, это потому, что иногда пользователь из Redux входит в componentWillReceiveProps до выполнения loadTeamsData, но я не знаю, почему это может привести к тому, что рейтинги не появятся. (Кроме того, я чувствую, что мой код дерьмо ... Любая критика c приветствуется!)

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

Когда отображаются рейтинги When ratings show up

Когда рейтинги не отображаются

Я веду журнал this.state.teams[0] и this.state.teams[0].thumbUp в методе рендеринга. Даже во время первого рендеринга и thumbUp, и thumbDown отображаются в this.state.teams[0], но this.state.teams[0].thumbUp кажется неопределенным.

When ratings don't show up

1 Ответ

0 голосов
/ 06 марта 2020

Мне удалось решить проблему. На самом деле проблема была в файле Rating. js, извините, что я не опубликовал этот файл, потому что я думал, что проблема должна быть в Home. js.

До, в файле Rating. js, я первоначально привел пользователя из redux, который вызвал проблему (я думаю, что он не сделал повторный рендеринг Rating, когда находился в Home. js вызов axios get произошел после componentWillReceiveProps) .

После вместо того, чтобы вводить пользователя из redux, я передал пользователя в Rating. js как реквизит из Home. js.

Несмотря на то, что теперь он работает нормально, я до сих пор не знаю, в чем именно заключалась проблема ... Я был бы очень признателен, если бы кто-то мог просветить меня! Также, пожалуйста, критикуйте мой код (т.е. где я могу улучшить)! СПАСИБО!

Рейтинг. 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);

Рейтинг. 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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...