2019年12月15日
プログラミング
React Hooksを使う【Reactで作るマラソンペースメーカー】
はじめに
新しい技術にチャレンジし続けるpalanのアドベントカレンダーDay15です!
昨日は『Adobeのデザインシステム、spectrumから学べるデザインの基礎
』についての記事でした。
このシリーズでは、Reactを使用し
前回、マラソンペース計算システムをCreate React Appでプロジェクトを作成し、Material-UIの使ってUIを作ってみました。
今回は、シリーズの続きとしてReact 16.8から導入されたReactのhookという機能について解説していきます。
フォームを使ってみる
まず、Material-UIのサンプルをコードを見てみましょう。
前回 の記事で使用した、こちらの選択フォームのコードを見ていきます。
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
以外にも useContext
や useEffect
、useReducer
などがあります。
今回のコードで解説していく前に、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
関連記事
2022年5月13日
Reactでオセロゲームを作る
2021年4月9日
Slack OAuth x React で Slack ユーザー認証を作ってみた!
2021年3月1日
Reactで使えるバリデーションライブラリを紹介!
2021年2月22日
Hasura Cloud × Auth0 × React でお手軽にTodoアプリを作ってみた!
2020年12月12日
Blitz.jsとTailwind CSSでメモ帳アプリの作成【第2弾】
2020年12月8日
コンポーネントを実装するときに意識すること
簡単に自分で作れるWebAR
「palanAR」はオンラインで簡単に作れるWebAR作成ツールです。WebARとはアプリを使用せずに、Webサイト上でARを体験できる新しい技術です。
palanARへpalanでは一緒に働く仲間を募集しています
正社員や業務委託、アルバイトやインターンなど雇用形態にこだわらず、
ベテランの方から業界未経験の方まで様々なかたのお力をお借りしたいと考えております。
運営メンバー
Eishi Saito 総務
SIerやスタートアップ、フリーランスを経て2016年11月にpalan(旧eishis)を設立。 マーケター・ディレクター・エンジニアなど何でも屋。 COBOLからReactまで色んなことやります。
sasakki デザイナー
アメリカの大学を卒業後、日本、シンガポールでデザイナーとして活動。
やまかわたかし デザイナー
フロントエンドデザイナー。デザインからHTML / CSS、JSの実装を担当しています。最近はReactやReact Nativeをよく触っています。
Sayaka Osanai デザイナー
Sketchだいすきプロダクトデザイナー。シンプルだけどちょっとかわいいデザインが得意。 好きな食べものは生ハムとお寿司とカレーです。
はらた エンジニア
サーバーサイドエンジニア Ruby on Railsを使った開発を行なっています
こぼり ともろう エンジニア
サーバーサイドエンジニア。SIerを経て2019年7月に入社。日々学習しながらRuby on Railsを使った開発を行っています。
ささい エンジニア
フロントエンドエンジニア WebGLとReactが強みと言えるように頑張ってます。
Damien
WebAR/VRの企画・開発をやっています。森に住んでいます。
ゲスト bagelee
かっきー
まりな
suzuki
miyagi
ogawa
雑食デザイナー。UI/UXデザインやコーディング、時々フロントエンドやってます。最近はARも。
いわもと
デザイナーをしています。 好きな食べ物はラーメンです。
taishi kobari
フロントエンドの開発を主に担当してます。Blitz.js好きです。
kubota shogo
サーバーサイドエンジニア。Ruby on Railsを使った開発を行いつつ月500kmほど走っています!
nishi tomoya
aihara
グラフィックデザイナーから、フロントエンドエンジニアになりました。最近はWebAR/VRの開発や、Blender、Unityを触っています。モノづくりとワンコが好きです。
nagao
SIerを経てアプリのエンジニアに。xR業界に興味があり、unityを使って開発をしたりしています。
Kainuma
サーバーサイドエンジニア Ruby on Railsを使った開発を行なっています
sugimoto
asama
ando
iwasawa ayane
oshimo
異業界からやってきたデザイナー。 palanARのUIをメインに担当してます。 これからたくさん吸収していきます!