2019年12月15日

プログラミング

React Hooksを使う【Reactで作るマラソンペースメーカー】

目次

  1. はじめに
  2. フォームを使ってみる
  3. React Hooksとは
  4. まとめ

はじめに

新しい技術にチャレンジし続けるpalanのアドベントカレンダーDay15です!

昨日は『Adobeのデザインシステム、spectrumから学べるデザインの基礎
』についての記事でした。

Adobeのデザインシステム、spectrumから学べるデザインの基礎

このシリーズでは、Reactを使用し
前回、マラソンペース計算システムをCreate React Appでプロジェクトを作成し、Material-UIの使ってUIを作ってみました。
今回は、シリーズの続きとしてReact 16.8から導入されたReactのhookという機能について解説していきます。

フォームを使ってみる

まず、Material-UIのサンプルをコードを見てみましょう。

前回 の記事で使用した、こちらの選択フォームのコードを見ていきます。
 2019-12-15 16.19.13.png (270.7 kB)

POINT!!

各サンプルの「<>」を押すと、サンプルコードが見れます。またその際に左側のJSマークではTSマークを使用することで、TypeScriptのコードも見ることができます!便利ですね!

色々とコードがありますが、シンプルに選択フォームだけを表示させるコードをApp.jsに書いていきます。

App.js


import React from 'react'; import { makeStyles } from '@material-ui/core/styles'; import InputLabel from '@material-ui/core/InputLabel'; import MenuItem from '@material-ui/core/MenuItem'; import FormControl from '@material-ui/core/FormControl'; import Select from '@material-ui/core/Select'; const useStyles = makeStyles(theme => ({ formControl: { margin: theme.spacing(1), minWidth: 120, }, })); export default function SimpleSelect() { const classes = useStyles(); const [age, setAge] = React.useState(''); const handleChange = event => { setAge(event.target.value); }; return ( <div> <FormControl className={classes.formControl}> <InputLabel id="demo-simple-select-label">Age</InputLabel> <Select labelId="demo-simple-select-label" id="demo-simple-select" value={age} onChange={handleChange} > <MenuItem value={10}>Ten</MenuItem> <MenuItem value={20}>Twenty</MenuItem> <MenuItem value={30}>Thirty</MenuItem> </Select> </FormControl> </div> ); }

それでは解説していきます。

これらのインポート設定は前回も解説しましたね。使用するコンポーネントを、最初にインポートしています。


import React from 'react'; import { makeStyles } from '@material-ui/core/styles'; import InputLabel from '@material-ui/core/InputLabel'; import MenuItem from '@material-ui/core/MenuItem'; import FormControl from '@material-ui/core/FormControl'; import Select from '@material-ui/core/Select';
const useStyles = makeStyles(theme => ({
  formControl: {
    margin: theme.spacing(1),
    minWidth: 120,
  },
}));

さて、次はmakeStyles()という関数が出てきました。
こちらは名前の通りスタイルを作るための関数で、スタイルシートをMaterial-UIで使用する為のものです。

こちらのドキュメント の通り、使い方としては、このようにスタイルを作る関数、もしくはスタイルオブジェクトを引数とし、戻り値としてhook関数を返します。
makeStyles(styles, [options]) => hook

さて、ここで聞き覚えの内hookというものが出てきました。
hookについては後ほど説明をしますが、現時点ではuseStylesというhook関数に、引数にtheme(テーマ)を指定し、formControlクラスを定義しています。
中でマージンや最小横幅を指定しています。

では、メインとなる関数コンポーネントであるSimpleSelect()を見ていきましょう。


export default function SimpleSelect() { const classes = useStyles(); const [age, setAge] = React.useState(''); const handleChange = event => { setAge(event.target.value); }; return ( <div> <FormControl className={classes.formControl}> <InputLabel id="demo-simple-select-label">Age</InputLabel> <Select labelId="demo-simple-select-label" id="demo-simple-select" value={age} onChange={handleChange} > <MenuItem value={10}>Ten</MenuItem> <MenuItem value={20}>Twenty</MenuItem> <MenuItem value={30}>Thirty</MenuItem> </Select> </FormControl> </div> );

ここで、hookを知らないReact経験者の方は「あれ?」と思われるかもしれません。
クラスコンポーネントでなく関数コンポーネントですし、にも関わらず状態(state)を保持できているように見えます。
これがReactの16.8以降のバージョンで採用された、hookと呼ばれる機能です。
※今回解説するuseState以外にも複数ある為、React Hooksと総称します。

React Hooksとは

React Hooks は、state などの React の機能を、 クラスを書かずに使えるようになる機能(API) です。

今回解説する useState以外にも useContextuseEffectuseReducerなどがあります。

今回のコードで解説していく前に、16.8より前の書き方(Material-UIのバージョン3系)はこちらです。


import React from 'react'; import ReactDOM from 'react-dom'; import PropTypes from 'prop-types'; import { withStyles } from '@material-ui/core/styles'; import Input from '@material-ui/core/Input'; import InputLabel from '@material-ui/core/InputLabel'; import MenuItem from '@material-ui/core/MenuItem'; import FormControl from '@material-ui/core/FormControl'; import Select from '@material-ui/core/Select'; const styles = theme => ({ root: { display: 'flex', flexWrap: 'wrap', }, formControl: { margin: theme.spacing.unit, minWidth: 120, }, selectEmpty: { marginTop: theme.spacing.unit * 2, }, }); class SimpleSelect extends React.Component { state = { age: '', labelWidth: 0, }; componentDidMount() { this.setState({ labelWidth: ReactDOM.findDOMNode(this.InputLabelRef).offsetWidth, }); } handleChange = event => { this.setState({ [event.target.name]: event.target.value }); }; render() { const { classes } = this.props; return ( <form className={classes.root} autoComplete="off"> <FormControl className={classes.formControl}> <InputLabel htmlFor="age-simple">Age</InputLabel> <Select value={this.state.age} onChange={this.handleChange} inputProps={{ name: 'age', id: 'age-simple', }} > <MenuItem value=""> <em>None</em> </MenuItem> <MenuItem value={10}>Ten</MenuItem> <MenuItem value={20}>Twenty</MenuItem> <MenuItem value={30}>Thirty</MenuItem> </Select> </FormControl> </form> ); } } SimpleSelect.propTypes = { classes: PropTypes.object.isRequired, }; export default withStyles(styles)(SimpleSelect);

注目すべき点は、当然クラスコンポーネントで定義されていること、またstateの初期値を設定していること、componentDidMount といったライフサイクルを使用している点です。

端的に言ってしまうと、hook(今回使用するuseState)はこれらのクラスコンポーネントで持っていた機能を関数コンポーネントでも利用できるようにしたことで、よりコードの見通しを良くすることができるものです。

useStateを使う

useStateは名前の通り、関数コンポーネント上でstateを扱う為のAPIです。
従来は関数コンポーネントではstate的に状態を保持することはできませんでしたが、useStateを使うことでそのような動的な関数を扱うことができます。

そちらの部分を抜粋して解説します。


const [age, setAge] = React.useState(''); const handleChange = event => { setAge(event.target.value); }; return ( <div> <FormControl className={classes.formControl}> <InputLabel id="demo-simple-select-label">Age</InputLabel> <Select labelId="demo-simple-select-label" id="demo-simple-select" value={age} onChange={handleChange} > <MenuItem value={10}>Ten</MenuItem> <MenuItem value={20}>Twenty</MenuItem> <MenuItem value={30}>Thirty</MenuItem> </Select> </FormControl> </div> ); }

const [age, setAge] = React.useState(''); でuseStateを使用しています。
1つ目のageにstateの初期値を設定しています。今回は特に値を設定していませんが、例えばconst [age, setAge] = React.useState(10);とすることで、ageには10がstateの初期値として入ります。
2つ目のsetAgeはstateを更新する為の関数です。

つまり、ageにstateの初期値を設定し、その更新にはsetAgeを使用するというものです。

次に、こちらで先程のsetAgeでeventのvalueでstateを更新していきます。


const handleChange = event => { setAge(event.target.value); };

さて、それでは肝心のフォーム部分を見ていきます。


return ( <div> <FormControl className={classes.formControl}> <InputLabel id="demo-simple-select-label">Age</InputLabel> <Select labelId="demo-simple-select-label" id="demo-simple-select" value={age} onChange={handleChange} > <MenuItem value={10}>Ten</MenuItem> <MenuItem value={20}>Twenty</MenuItem> <MenuItem value={30}>Thirty</MenuItem> </Select> </FormControl> </div> );

そこまで難しい点はなさそうですね!
Selectコンポーネントで、onChangeイベントで先程のhandleChangeを呼び出しています。その際のvalueはageです。
const [age, setAge] = React.useState(''); こちらで初期値は設定しませんでしたが、例えばReact.useState(10);とすることで、ここのvalueには10が設定されます。

MenuItemもMaterial-UIのコンポーネントで、Selectコンポーネントでの選択肢となります。
セレクトボックスで値を選択することで、onChangeが走り、setAgeでstateを更新し、Selectが更新される、という流れです。

まとめ

React Hooksの中でもだいぶ簡単な部分を今回はご紹介しました。
かなり話題をよんだ新機能ですし、構えてしまう部分もあるかもしれませんが、慣れてしまうとコードの可読性も上がり、設計もしやすくなるものです。

また公式ドキュメントに 100% 後方互換です とありますし、クラスコンポーネント自体がなくなることもなく、上手く棲み分けしていくことが重要です。
次回以降は、サービスの本機能である計算処理を実装していきます。

Reactのお仕事に関するご相談

Bageleeの運営会社、palanではReactに関するお仕事のご相談を無料で承っております。
zoomなどのオンラインミーティング、お電話、貴社への訪問、いずれも可能です。
ぜひお気軽にご相談ください。

無料相談フォームへ

1

0

AUTHOR

eishis

Eishi Saito 総務

SIerやスタートアップ、フリーランスを経て2016年11月にpalan(旧eishis)を設立。 マーケター・ディレクター・エンジニアなど何でも屋。 COBOLからReactまで色んなことやります。

アプリでもっと便利に!気になる記事をチェック!

記事のお気に入り登録やランキングが表示される昨日に対応!毎日の情報収集や調べ物にもっと身近なメディアになりました。

簡単に自分で作れるWebAR

「palanAR」はオンラインで簡単に作れるWebAR作成ツールです。WebARとはアプリを使用せずに、Webサイト上でARを体験できる新しい技術です。

palanARへ
palanar

palanはWebARの開発を
行っています

弊社では企画からサービスの公開終了まで一緒に関わらせていただきます。 企画からシステム開発、3DCG、デザインまで一貫して承ります。

webar_waterpark

palanでは一緒に働く仲間を募集しています

正社員や業務委託、アルバイトやインターンなど雇用形態にこだわらず、
ベテランの方から業界未経験の方まで様々なかたのお力をお借りしたいと考えております。

話を聞いてみたい

運営メンバー

eishis

Eishi Saito 総務

SIerやスタートアップ、フリーランスを経て2016年11月にpalan(旧eishis)を設立。 マーケター・ディレクター・エンジニアなど何でも屋。 COBOLからReactまで色んなことやります。

sasakki デザイナー

アメリカの大学を卒業後、日本、シンガポールでデザイナーとして活動。

yamakawa

やまかわたかし デザイナー

フロントエンドデザイナー。デザインからHTML / CSS、JSの実装を担当しています。最近はReactやReact Nativeをよく触っています。

Sayaka Osanai デザイナー

Sketchだいすきプロダクトデザイナー。シンプルだけどちょっとかわいいデザインが得意。 好きな食べものは生ハムとお寿司とカレーです。

はらた

はらた エンジニア

サーバーサイドエンジニア Ruby on Railsを使った開発を行なっています

kobori

こぼり ともろう エンジニア

サーバーサイドエンジニア。SIerを経て2019年7月に入社。日々学習しながらRuby on Railsを使った開発を行っています。

sasai

ささい エンジニア

フロントエンドエンジニア WebGLとReactが強みと言えるように頑張ってます。

damien

Damien

WebAR/VRの企画・開発をやっています。森に住んでいます。

ゲスト bagelee

ゲスト bagelee

かっきー

かっきー

まりな

まりな

suzuki

suzuki

miyagi

ogawa

ogawa

雑食デザイナー。UI/UXデザインやコーディング、時々フロントエンドやってます。最近はARも。

いわもと

いわもと

デザイナーをしています。 好きな食べ物はラーメンです。

kobari

taishi kobari

フロントエンドの開発を主に担当してます。Blitz.js好きです。

shogokubota

kubota shogo

サーバーサイドエンジニア。Ruby on Railsを使った開発を行いつつ月500kmほど走っています!

nishi tomoya

aihara

aihara

グラフィックデザイナーから、フロントエンドエンジニアになりました。最近はWebAR/VRの開発や、Blender、Unityを触っています。モノづくりとワンコが好きです。

nagao

SIerを経てアプリのエンジニアに。xR業界に興味があり、unityを使って開発をしたりしています。

kainuma

Kainuma

サーバーサイドエンジニア Ruby on Railsを使った開発を行なっています

sugimoto

sugimoto

asama

ando

iwasawa ayane

oshimo

yoko oshimo

異業界からやってきたデザイナー。palanARのUIをメインに担当してます。これからたくさん吸収していきます!

CONTACT PAGE TOP