Javontay Mcelroy
Javontay Mcelroy

Reputation: 25

Increment and Decrement Counters not Setting State Correctly

I'm trying to create a simple component that will act as a counter! There are two counters, one for counting repetitions, and another for counting amounts lifted. For some reason, the functions that I write are not working as intended.

The expected result is, when I click on the up or down arrow for say, reps, it should update THAT number in the state. Same goes for the amount lifted.

But what's happening is, when I click the up and down arrow for let's say, reps again, it works and increments and decrements correctly, but when I then click the arrows to increment and decrement the amount lifted, NaN is returned and then if I click on the rep arrows after that, that too then returns NaN.

Here's my relevant code:

class TrackProgress extends Component {
  constructor(props) {
    super(props);
    this.state = {
      id: parseInt(this.props.match.params.id),
      exercise: [],
      trackProgress: {
        exercise_id: parseInt(this.props.match.params.id),
        date: "",
        reps: 0,
        amountLifted: 0
      }
    };
  }

  handleChanges = e => {
    this.setState({
      trackProgress: {
        ...this.state.trackProgress,
        [e.target.name]: e.target.value
      }
    });
  };

  repsIncrease = () => {
    this.setState({
      trackProgress: {
        reps: this.state.trackProgress.reps + 1
      }
    });
  };

  repsDecrease = () => {
    this.setState({
      trackProgress: {
        reps: this.state.trackProgress.reps - 1
      }
    });
  };

  amountLiftedIncrease = () => {
    this.setState({
      trackProgress: {
        amountLifted: this.state.trackProgress.amountLifted + 1
      }
    });
  };

  amountLiftedDecrease = () => {
    this.setState({
      trackProgress: {
        amountLifted: this.state.trackProgress.amountLifted - 1
      }
    });
  };

render() {
    return (
      <div className="track-progress-container">
        <div className="track-progress-content">
          <div className="heading">
            <h1>Start Tracking</h1>
            <h2>{this.state.exercise.exerciseTitle}</h2>
          </div>
          <form className="tracking-form-container" onSubmit={this.onSubmit}>
            <div className="rep-lift-flex">
              <div>
                <h6>REPS</h6>
                <input
                  name="reps"
                  type="text"
                  placeholder="OO"
                  value={this.state.trackProgress.reps}
                  onChange={this.handleChanges}
                />
              </div>
              <div>
                <h6>LIFTED</h6>
                <input
                  name="amountLifted"
                  type="text"
                  placeholder="OO"
                  value={this.state.trackProgress.amountLifted}
                  onChange={this.handleChanges}
                />
              </div>
            </div>
            <div className="arrow-container">
              <div className="rep-arrows">
                <img
                  src={down}
                  alt="decrease"
                  name="decrementReps"
                  className={
                    this.state.trackProgress.reps === 0 ? "inactive" : ""
                  }
                  onClick={this.repsDecrease}
                />
                <img
                  src={up}
                  alt="increase"
                  name="incrementReps"
                  onClick={this.repsIncrease}
                />
              </div>
              <div className="lift-arrows">
                <img
                  src={down}
                  alt="decrease"
                  name="decrementLifted"
                  onClick={this.amountLiftedDecrease}
                  className={
                    this.state.trackProgress.amountLifted === 0
                      ? "inactive"
                      : ""
                  }
                />
                <img
                  src={up}
                  alt="increase"
                  name="incrementLifted"
                  onClick={this.amountLiftedIncrease}
                />
              </div>
            </div>
            <h6>Date</h6>
            <input
              name="date"
              type="date"
              placeholder="e.g. June 11, 2019"
              value={this.state.trackProgress.date}
              onChange={this.handleChanges}
              className="date"
            />
            <button type="submit" className="track-btn">
              TRACK EXERCISE
            </button>
          </form>
        </div>
      </div>
    );
  }
}

export default TrackProgress;

Here's were my initial functions before I wrote out more specific function. They both produced the same results.

reps = event => {
    if (event.target.name === "incrementReps") {
      this.setState({
        trackProgress: {
          reps: this.state.trackProgress.reps + 1
        }
      });
    } else if (event.target.name === "decrementReps") {
      this.setState({
        trackProgress: {
          reps: this.state.trackProgress.reps - 1
        }
      });
    }
  };

  amountLifted = event => {
    if (event.target.name === "incrementLifted") {
      this.setState({
        trackProgress: {
          amountLifted: this.state.trackProgress.amountLifted + 1
        }
      });
    } else if (event.target.name === "decrementLifted") {
      this.setState({
        trackProgress: {
          amountLifted: this.state.trackProgress.amountLifted - 1
        }
      });
    }
  };

I could be missing crucial logic or not account for something, I've been staring at this for hours, so help solving this would be greatly appreciated! Thank you!!

Upvotes: 1

Views: 93

Answers (1)

James Paterson
James Paterson

Reputation: 2890

You are replacing the whole trackProgress object when you update either reps or amount lifted. Your state is:

this.state = {
     id: parseInt(this.props.match.params.id),
     exercise: [],
     trackProgress: {
         exercise_id: parseInt(this.props.match.params.id),
         date: "",
         reps: 0,
         amountLifted: 0
     }
}

Calling your update function for reps or currently replaces the entire trackProgress object, instead of just updating the properties you want.

repsIncrease = () => {
    this.setState({
        trackProgress: {
            reps: this.state.trackProgress.reps + 1
        }
    });
}; 

Leads to:

state = {
     id: 1,
     exercise: [],
     trackProgress: {
         reps: 1,
     }
}

To fix this, you can include all the previous properties in your repsIncrease/decrease function, or use the spread operator to automatically fill them out. Here's an example of the fixed repsIncrease function.

repsIncrease = () => {
    this.setState({
        trackProgress: {
            ...this.state.trackProgress,
            reps: this.state.trackProgress.reps + 1
        }
    });
}; 

Upvotes: 2

Related Questions