0

I have three election contestant that I want to update their vote counts by making axios call to server backend.

Everything is working fine.

Here is an example of json response from axios call.

[{ "id": "1", "name": "contestant 1", "vote": "300" }]

My Issue:

My only issue is the loading event. When I click on first contestant to update its vote result via axios call. Instead of the application to display Content Loading... only for the click contestant button, it will display Content Loading... for all the three contestant button.

What I want:

Please how do I display Content Loading... only for the clicked contestant buttons

I guess this has to do with the Id of the clicked contestant. I have also tried this but no way

if (person.id === person_id){
this.setState({ loading: true });
}

Here is the code

import React, { Component, Fragment } from "react";
import { render } from "react-dom";


class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      data: [],
      loading: false,
 isLoading: true
    };
  }

  componentDidMount() {
    this.setState({
      data: [
        { id: "1", name: "contestant 1", vote: "3" },
        { id: "2", name: "contestant 2", vote: "6" },
        { id: "3", name: "contestant 3", vote: "2" }
      ]
    });
  }


  handleVote(person_id, person_vote) {
    const data_vote = {
      person_id: person_id,
      person_vote: person_vote
    };




this.setState({ loading: true }, () => {

 axios.get("http://localhost/apidb_react/result.json", { data_vote })
      .then(response => {
        const newData = this.state.data.map(person => {
       if (person.id !== person_id) return person;
       return { ...person,vote: response.data[0].vote };
        });
        this.setState(state => ({
          data: newData,
loading: false,
        }));
      })
      .catch(error => {
        console.log(error);
      });

});// close loading
  }

  render() {


let data_loading;
    if (this.state.loading) {
      data_loading = "Content Loading......"
    }


    return (
      <span>
        <label>
          <ul>
            {this.state.data.map(person => (
              <li key={person.id}>
                {person.name} --(vote count: {person.vote})
                <br />
{data_loading}
                <button
                  type="button"

                  onClick={() => this.handleVote(person.id, person.vote)}
                >  Get Vote</button>
              </li>
            ))}
          </ul>
        </label>
      </span>
    );
  }
}
2
  • Change data to { id: "1", name: "contestant 1", vote: "3", isLoading: false }, and then {person.isLoading && "Content Loading.."} instead of {data_loading}. You get the idea? Commented Mar 5, 2019 at 16:04
  • @FortyTwo that concept is not working. not showing any result. no error message Commented Mar 5, 2019 at 16:20

1 Answer 1

1

You will need a separate loading state for every contestant. So the logical next step would be to create Contestant component having it's own state and own UI for reflecting that state to the user.

Something like this:

class Contestant extends React.Component {
  static defaultProps = {
    onVote: () => {},
    onError: () => {}
  };

  constructor() {
    super();
    this.state = {
      isLoading: false
    };
  }

  handleVote(person_id, person_vote) {
    const data_vote = {
      person_id: person_id,
      person_vote: person_vote
    };

    this.setState({ isLoading: true });
    axios
      .get("http://localhost/apidb_react/result.json", { data_vote })
      .then(response => {
        this.props.onVote(person_id, response.data[0].vote);
        this.setState({ isLoading: false });
      })
      .catch(error => {
        this.props.onError(error);
      });
  }

  render() {
    const { person } = this.props;
    const { isLoading } = this.state;

    return (
      <li key={person.id}>
        {isLoading
          ? "Content Loading......"
          : `${person.name} --(vote count: ${person.vote})`}
        <br />
        <button
          type="button"
          onClick={() => this.handleVote(person.id, person.vote)}
        >
          Get Vote
        </button>
      </li>
    );
  }
}

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      data: []
    };
  }

  componentDidMount() {
    this.setState({
      data: [
        { id: "1", name: "contestant 1", vote: "3" },
        { id: "2", name: "contestant 2", vote: "6" },
        { id: "3", name: "contestant 3", vote: "2" }
      ]
    });
  }

  onVote = (person_id, vote) => {
    const { data } = this.state;

    this.setState({
      data: data.map(person => {
        if (person.id !== person_id) return person;
        return { ...person, vote };
      })
    });
  };

  render() {
    return (
      <span>
        <label>
          <ul>
            {this.state.data.map(person => (
              <Contestant
                key={person.id}
                person={person}
                onVote={this.onVote}
              />
            ))}
          </ul>
        </label>
      </span>
    );
  }
}

Somewhat functional sandbox: https://codesandbox.io/s/p7q3qylwj0. Obviously you will need to hit a real endpoint there, instead of:http://localhost/apidb_react/result.json

Sign up to request clarification or add additional context in comments.

2 Comments

That is what am still think on how to figure it out
Thanks Sir Jayarjo

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.