Skip to content

Having trouble creating an adjustable timer using ReactJS, changing state of a child item to parent

CodeSandbox example of my code

I’m trying to make a timer app with a unique UI for the timer. my issue is i cant seem to adjust the timer without it glitching out.

when i try to lower the time, it adds a new number under the “arrow” button. instead of doing this, it should subtract the number above it.

If the up arrow is clicked the time goes to 1, but if we click the down arrow, the time should go back to 0. right now the timer only goes up to 1 which is fine for the purpose of this question.

i know im doing something wrong, i just cant seem to understand it. i would really like to be able to do it using the two components i have set up just to keep the code maintainable.

the two important components are:

TimerSettings.jsx, and Arrows.jsx

CodeSandbox example of my code

import React, { Component } from "react";
import Arrows from "./Arrows";
class TimerSettings extends Component {
    constructor(props) {
        super(props);
        this.state = { timeData: 0 };
    }
    render() {
        let changeTime = ["up", "up", "up", "up", "up", "up", "down", "down", "down", "down", "down", "down"];

        return (
            <React.Fragment>
                <div className="container">
                    <div className="row">
                        <div className="col s12" id="timer-settings-block">
                            <h1 className="center-align" id="timer-settings-title">
                                Create Timer
                            </h1>
                            {changeTime.map((item, uid) => (
                                <Arrows status={item} uid={uid} timeData={this.state.timeData} /*changeTime={() => this.handleTime()}*/ />
                            ))}
                        </div>
                    </div>
                </div>
            </React.Fragment>
        );
    }
    handleTime = () => {
        this.setState({ timeData: 1 });
    };
}

export default TimerSettings;

Arrows.jsx – child component

import React, { Component } from "react";

class Arrows extends Component {
    constructor(props) {
        super(props);
        this.state = { flip: "1", timeData: 0 };
        this.posTime = React.createRef();
        this.negTime = React.createRef();
    }

    render() {
        return (
            <p className="center-align">
                <div className="col s2">
                    <div className="col s6">
                        <h4
                            style={{ transform: "scaley(" + this.state.flip + ")" }}
                            className="move-time"
                            id={"move-first-" + this.props.uid}
                            ref={this.negTime + this.props.uid}
                            /*onClick={this.props.changeTime}*/
                            onClick={this.handleTime}
                        >
                            ^
                        </h4>
                        <h3>{this.state.timeData}</h3>
                    </div>
                </div>
            </p>
        );
    }

    handleTime = () => {
        this.setState({ timeData: 1 });
        if (this.state.flip === "-1") {
            this.setState({ timeData: 0 });
        }
    };

    componentDidMount = () => {
        if (this.props.status === "down") {
            this.setState({ flip: "-1", timeData: null });
        }
    };
}

export default Arrows;

Answer

You need to render both up and down arrows in the Arrow component so the up and down arrows can effect the same state.

class Arrows extends Component {
  constructor(props) {
    super(props);
    this.state = { timeData: 0 };
    this.posTime = React.createRef();
    this.negTime = React.createRef();
  }

  handleTime = (val) => () => {
    this.setState((prevState) => ({
      timeData: prevState.timeData + val
    }));
  };

  render() {
    return (
      <p className="center-align">
        <div className="col s2">
          <div className="col s6">
            <h4
              className="move-time"
              id={"move-first-" + this.props.uid + "-up"}
              ref={this.posTime}
              onClick={this.handleTime(1)}
            >
              ^
            </h4>
            <h3>{this.state.timeData}</h3>
            <h4
              style={{ transform: "scaley(-1)" }}
              className="move-time"
              id={"move-first-" + this.props.uid + "-down"}
              ref={this.negTime}
              onClick={this.handleTime(-1)}
            >
              ^
            </h4>
          </div>
        </div>
      </p>
    );
  }
}

And instead of rendering out 12 (6 up/6 down) you just render an array of 6 Arrow components.

class TimerSettings extends Component {
  constructor(props) {
    super(props);
    this.state = { timeData: 0 };
  }

  handleTime = () => {
    this.setState({ timeData: 1 });
  };

  render() {
    let changeTime = [...Array(6).keys()];

    return (
      <React.Fragment>
        <div className="container">
          <div className="row">
            <div className="col s12" id="timer-settings-block">
              <h1 className="center-align" id="timer-settings-title">
                Create Timer
              </h1>
              {changeTime.map((item, uid) => (
                <Arrows
                  key={uid}
                  status={item}
                  uid={uid}
                  timeData={this.state.timeData}
                />
              ))}
            </div>
          </div>
        </div>
      </React.Fragment>
    );
  }
}

Edit having-trouble-creating-an-adjustable-timer-using-reactjs-changing-state-of-a-c

enter image description here