React - pomodoro - onClick not updating

Hi there,

I am creating a pomodoro from scratch and am stuck.

I am confused about the following:

if i initialise a state to 0 and pass it down to its component with a different number (in my case its initialised with 25 and i pass it to the button with 5), when i do the onClick and i want to update the timer, should it not update the state with 5?

Perhaps i should split out the “value” of the button and the state object itself so they don’t conflict like this. is that where the error is coming from?

thanks

(how to update the timer to 5 minutes when i click 5 minutes)


App.js: 

export class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      minutes: 25,
      seconds: 0,
      button: ""
    };
  }

  render() {
    return (
      <div>
        <Timer minutes={this.state.minutes} seconds={0} />
        <TimerSetButton minutes={25} seconds={0} />
        <TimerSetButton minutes={5} seconds={0} />
        <TimerUpdateButton button={"start"} />
        <TimerUpdateButton button={"stop"} />
        <TimerUpdateButton button={"reset"} />
      </div>
    );
  }
}

export default App;


import React, { Component } from "react";

export class TimerSetButton extends Component {
  alterInitialTime() {
    this.setState({
      minutes: this.props.minutes
    });
  }

  render() {
    return (
      <div>
        <button onClick={() => this.alterInitialTime()}>
          {`${this.props.minutes} minutes`}
        </button>
      </div>
    );
  }
}

export default TimerSetButton;

so i did manage to update the state in the component but it does not pass up back into the timer?

import React, { Component } from "react";

export class TimerSetButton extends Component {
  alterInitialTime() {
    this.setState({
      minutes: this.props.minutes
    });
  }

  render() {
    return (
      <div>
        <button onClick={() => this.alterInitialTime(this.props.minutes)}>
          {`${this.props.minutes} minutes`}
        </button>
      </div>
    );
  }
}

export default TimerSetButton;

Short answer; when you click the button you are updating the state of TimerSetButton NOT App

You’ll need move the alterInitialTime function to App.js and then pass it down has a property.

App.js: 

export class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      minutes: 25,
      seconds: 0,
      button: ""
    };
        this.FUNCTION = this.FUNCTION.bind(this);
  }

FUNCTION () {
 *code*
}

  render() {
    return (
      <div>
        <Timer minutes={this.state.minutes} seconds={0}    anyPropName={this.FUNCTION}  />

      </div>
    );
  }
}

export default App;

*then you could call it with <button onClick={ this.props.anyPropName }>

am i doing something wrong? still renders but the button does not update it:



export class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      minutes: 25,
      seconds: 0,
      button: ""
    };

    this.alterInitialTime = this.alterInitialTime.bind(this);
  }

  alterInitialTime() {
    this.setState({
      minutes: this.props.minutes
    });
  }

  render() {
    return (
      <div>
        <Timer
          minutes={this.state.minutes}
          seconds={0}
          alterTime={this.alterInitialTime}
        />
        <TimerSetButton minutes={25} seconds={0} />
        <TimerSetButton minutes={5} seconds={0} />
        <TimerUpdateButton button={"start"} />
        <TimerUpdateButton button={"stop"} />
        <TimerUpdateButton button={"reset"} />
      </div>
    );
  }
}

export default App;

Try this. It should set it to 999. Then read the console log to see your options.

alterInitialTime(i) {
    console.log('THIS', this.props)
    console.log('TARGET', i.target)
    this.setState({
      minutes: 999
    });
  }

nothing is happening still. no update:


export class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      minutes: 25,
      seconds: 0,
      button: ""
    };

    this.alterInitialTime = this.alterInitialTime.bind(this);
  }

  alterInitialTime(i) {
    console.log("THIS", this.props);
    console.log("TARGET", i.target);
    this.setState({
      minutes: 999
    });
  }

  render() {
    return (
      <div>
        <Timer
          minutes={this.state.minutes}
          seconds={0}
          alterTime={this.alterInitialTime}
        />
        <TimerSetButton minutes={25} seconds={0} />
        <TimerSetButton minutes={5} seconds={0} />
        <TimerUpdateButton button={"start"} />
        <TimerUpdateButton button={"stop"} />
        <TimerUpdateButton button={"reset"} />
      </div>
    );
  }
}

export default App;

This looks good too me;

what does component <Timer> look like?

import React, { Component } from "react";

export class Timer extends Component {
  render() {
    return <div>{`${this.props.minutes}:${this.props.seconds}0`}</div>;
  }
}

export default Timer;

and below is the timersetbutton:

import React, { Component } from "react";

export class TimerSetButton extends Component {
  render() {
    return (
      <div>
        <button onClick={this.props.alterTime}>
          {`${this.props.minutes} minutes`}
        </button>
      </div>
    );
  }
}

export default TimerSetButton;

return <div onClick={this.props.alterTime} >{${this.props.minutes}:${this.props.seconds}0}</div>

should trigger the alterInitialTime function in App.js at set timer to 999.

ah ok, so this, if i ipress the timer, it will update the timer.

Yeah… I see now. I was confused for a minute too…

You want the function to the Buttons…

In the code, <Timer> has been given the onClick function. You want the buttons to get alterTime={this.alterInitialTime} in the App.js

the ‘999’ is hard coded. But say you had 3 buttons, each with id=10,id=20,id=30… then you could set the timer based on the button pressed because you can read the id. Honestly, i’m not sure if the i is needed or you can just read target.id by itself.

 alterInitialTime(i) {
    console.log("TARGET", i.target);
    this.setState({
      minutes: i.target.id //10, 20, 30 
    });
  }

i was just going to ask “cant we use the i.target” to target each button. thanks

No problem. good luck with the project!

I’m still learning myself, but I want to note that I’d suggest to build your components together…

so instead of having

        <TimerUpdateButton button={"start"} />
        <TimerUpdateButton button={"stop"} />
        <TimerUpdateButton button={"reset"} />
``

in you App.js, just have 1 single component that builds all those buttons.
` <TimerUpdateButton .... />

Basically if they are all going to be in the same 'container' make it a single component. Like a headerbar for a website, just put all of the code into header.js and 1 <header /> into react. Then you can use that same component in new projects easily :)

so for the timerupdatebutton, i should just copy and paste the div three times for each button right?

import React, { Component } from "react";

export class TimerUpdateButton extends Component {
  render() {
    return (
      <div>
        <button>{this.props.button}</button>
      </div>]
 <div>
        <button>{this.props.button}</button>
      </div>
 <div>
        <button>{this.props.button}</button>
      </div>
    );
  }
}

export default TimerUpdateButton;

yup. and give each button an id. so you know which one you click on.

1 Like