0

I am working on a stopwatch app using ReactJS and Electron. I have a Timer component, which keeps track of the time and displays the clock & controls.

The controls will be made up of three buttons: Play, Pause, and Stop. These Button components are completely unrelated to the Timer component.

My question is: if I have a handleStopClick() function in the Timer component, how can I call it from the StopButton component?

Note: there is currently no Play/Pause functionality. The Timer simply starts when mounted and a single Stop button should clear it. I'll add the rest when I've sorted this out.

Here is Timer.jsx:

import '../assets/css/App.css';
import React, { Component } from 'react';
import PlayButton from './PlayButton'; // No function
import PauseButton from './PauseButton';
import StopButton from './StopButton';

class Timer extends Component {
    constructor(props) {
        super(props);
        this.state = {
            isRunning: false,
            secondsElapsed: 0
        };
    }

    getHours() {
        return ('0' + Math.floor(this.state.secondsElapsed / 3600)).slice(-2);
    }

    getMinutes() {
        return ('0' + Math.floor(this.state.secondsElapsed / 60) % 60).slice(-2);
    }

    getSeconds() {
        return ('0' + this.state.secondsElapsed % 60).slice(-2);
    }

    handleStopClick() {
        clearInterval(this.incrementer);
    }

    componentDidMount() {
        this.isRunning = true;
        console.log(this.isRunning);

        var _this = this; // reference to component instance

        this.incrementer = setInterval( () => {
            _this.setState({
                secondsElapsed: (_this.state.secondsElapsed + 1)
            });
        }, 1000)
    }

    playOrPauseButton() {
        if (this.isRunning) {return <PauseButton />}
        else {return <PlayButton />}
    }

    render() {
        return (
            <div>
                {this.playOrPauseButton()}
                <StopButton /> <hr />
                {this.getHours()} : {this.getMinutes()} : {this.getSeconds()}
            </div>
        );
    }
}

export default Timer;

And StopButton.jsx:

import '../assets/css/App.css';
import React, { Component } from 'react';
import Timer from './Timer';

class StopButton extends Component {
    handleClick () {
        console.log('this is: ', this);
        Timer.handleStopClick() // here's where I'd like to call Timer's function
    }

    render() {
        return (
            <button onClick={(e) => this.handleClick(e)}>
                &#9632;
            </button>
        );
    }
}

export default StopButton;
nxheller
  • 115
  • 9

1 Answers1

1

You can pass the handleStopClick method into the onClick handler of your StopButton component:

constructor(props) {
    ...
    this.handleStopClick = this.handleStopClick.bind(this);
}

render() {
    return (
        ...
        <StopButton onClick={this.handleStopClick}/>
    );
}

or, since it looks like you have additional things you want to do when the StopButton is clicked, you can pass it as a normal prop and reference it in the child component's handleStopClick method:

// Timer

render() {
    return (
        ...
        <StopButton parentStopClick={this.handleStopClick}/>
    );
}

// StopButton

handleStopClick() {
    ...
    this.props.parentStopClick();
}
Graham
  • 141
  • 4
  • I don't think I have any parent-child relationships with my components. They are simply two separate .jsx files, by my understanding. Is `parentStopClick` being defined, instantiated, and assigned a value all at once? – nxheller Apr 13 '17 at 21:50
  • Hmm...I'm getting a `Uncaught TypeError: this.props.parentStopClick is not a function` error when I click the Stop button now – nxheller Apr 13 '17 at 22:00
  • The parent-child relationship comes from rendering `StopButton` within `Timer` - that's how you can pass props down from `Timer`. Since `StopButton` is written in ES2015 class syntax, you have to call `super()` in its [constructor method](http://stackoverflow.com/a/34076378/7864431) if you want to reference props on the instance (`this.props`). – Graham Apr 13 '17 at 22:09
  • Thanks. I plugged in your suggestions above and got the error: `Uncaught TypeError: this.props.parentStopClick is not a function` when I click the StopButton. Do you have any ideas as to why? – nxheller Apr 13 '17 at 22:47
  • It may be related to binding - my previous comment addressed the `StopButton` constructor method but you could get that `TypeError` if you aren't binding the `parentStopClick` function in the constructor of your `Timer` component. [This SO post](http://stackoverflow.com/questions/31141444/reactjs-with-es6-this-props-is-not-a-function-when-i-communicate-two-components) has some info that might help you out. – Graham Apr 13 '17 at 23:22