JavaScript
JSX
react.js
React
Electron

Electron と React でPomodoro Timerアプリを作ってみる

More than 3 years have passed since last update.


はじめに

React.js, JSX, ElectronでPomodoro Technique(ポモドーロテクニック)を実践できるタイマーアプリを作ってみました。

https://github.com/massa142/pomodoro

pomodoro_timer.png


作った理由

PHPカンファレンス2015でのKenji Akiyamaさんの発表資料を見て、「Electron面白そう!ちょっと試してみよ」となったためです。

Electronからクロスプラットフォーム・アプリケーションの歴史を考える

ただ作りたいものがパッと思いつかなかったので、Akiyamaさんと同じPomodoro Technique用のタイマーアプリをReact.jsで作ってみることにしました。


Pomodoro Techniqueとは


1.達成しようとするタスクを選ぶ

2.キッチンタイマーで25分を設定する

3.タイマーが鳴るまでタスクに集中する

4.少し休憩する(5分程度でOK)

5.ステップ2~4を4回繰り返したら、少し長めに休憩する


今日から始める生産性アップ術。ポモドーロ・テクニック再入門ガイド

rebuild.fm ep.93でもちょっと話題にあがってました。

http://rebuild.fm/93/


環境構築

ElectronもReactも今回初めて触ったので開発環境整えるのどうしようかなーと思ってたら、@Quramyさんが「ぼくのかんがえたさいきょうのElectron」開発環境を作ってくれていました。

ありがたくこのboilerplateを使わせて頂きました。


内部構成

.

├── README.md
├── bower.json
├── bower_components
├── dist
├── gulpfile.js
├── node_modules
├── package.json
├── release
└── src
├── app.js
├── assets
│   └── images
│   ├── electron.svg
│   └── electron2.svg
├── browser
│   └── menu
│   └── appMenu.js
├── renderer
│   ├── bootstrap.js
│   ├── components
│   │   └── main.jsx
│   └── index.html
└── styles
└── main.scss


main.jsx

'use strict';

import React from 'react';
import notifier from 'node-notifier';

export class Main extends React.Component {

constructor(props) {
super(props);
this.state = {
isStart: false,
isBreak: false,
time: this.props.duration
}
this.handleStartClicked = ::this.handleStartClicked;
this.handleResetClicked = ::this.handleResetClicked;
this.tick = ::this.tick;
}

handleStartClicked() {
if (!this.state.isStart) {
this.interval = setInterval(this.tick, 1000);
this.setState({isStart: true});
} else {
clearInterval(this.interval);
this.setState({isStart: false});
}
}

handleResetClicked() {
this.reset();
}

tick() {
this.setState({time: this.state.time - 1});
if (this.state.time === 0) {
this.finishEvent();
}
}

finishEvent() {
if (this.state.isBreak) {
this.reset();
this.notify('Break is over!');
} else {
this.break();
this.notify('Good work!');
}
}

break() {
this.setState({
isStart: true,
isBreak: true,
time: this.props.breakTime
});
}

reset() {
clearInterval(this.interval);
this.setState({
isStart: false,
isBreak: false,
time: this.props.duration
});
}

notify(message) {
notifier.notify({
'title': 'Pomodoro Timer',
'message': message
});
}

converter = {
s2m(s) {
let minutes = Math.floor(s / 60);
let seconds = s % 60;
return ('0' + minutes.toString()).slice(-2) + ':' + ('0' + seconds.toString()).slice(-2);
}
};

render() {
return (
<div className="container">
<div className="jumbotron main">
<h2>Pomodoro Timer</h2>
<img src={this.state.isBreak ? "../assets/images/electron2.svg" : "../assets/images/electron.svg"} alt="" width="128px"></img>
<h2>{this.converter.s2m(this.state.time)}</h2>
<div>
<button type="button" className="btn btn-primary" onClick={this.handleStartClicked}>
{this.state.isStart ? "Pause" : "Start"}
</button>
<button type="button" className="btn btn-warning" onClick={this.handleResetClicked}>Reset</button>
</div>
</div>
</div>
);
}
}

Main.defaultProps = {
duration: 1500,
breakTime: 300
};


感想