はじめに
**React**は、Facebookとコミュニティによって開発されているユーザーインターフェース構築のためのJavaScriptライブラリです。大体の人は、JavaScriptでReactを書くと思いますが、ReactとTypeScriptの相性が非常に良いので、ぜひTypeScriptでReactを始めてみてはいかがでしょうか?また、Reactで開発を進めていく中で、もっとも煩わしくなるのが状態(state)管理です。これを解消するために、ReduxやUnduxを使うのですが、正直難しいです笑。unstatedを使えば、比較的簡単に状態管理ができると聞いたので、今回は、unstatedを使ってみたいと思います。
開発環境の構築
nodeのインストール
こちらのページから、推奨版をインストールしてください。macの人はnodebrew、Windowsの人はnodistを使うと、nodeのバージョンを簡単に切り替えることができるので、そっちを使ったほうがいいかもしれないです。
create-react-appコマンドのインストール
ターミナル、またはコマンドプロンプトを開いて、以下のコマンドを打ち込んでください。
$ npm install -g create-react-app
アプリの雛形を作る
create-react-appコマンドを使えば一発でアプリの雛形ができる。オプションで**--template typescript**をつけることで、TypeScriptを導入できる。
$ create-react-app my-app --template typescript
サーバーを開始する
cdコマンドで、先ほど作ったアプリに移動し、npm startで起動する。
$ cd my-app
$ npm start
http://localhost:3000/ にアクセスして、このような画面が出てきたら成功。
カウントアプリを作る
今回は、簡単なカウントアプリを作ってみたいと思います。
コンポーネント(部品)作り
今回は、カウントを表示するコンポーネント(Display.tsx)とカウントを増やすボタン(Button.tsx)の二つを作りたいと思います。src直下に、componentsフォルダを作り、その中にDisplay.tsxとButton.tsxを作ります。
src-
|-components
|-Display.tsx
|-Button.tsx
import React from 'react'
const Display: React.SFC = () => {
return (
<div>
<h1>0</h1>
</div>
)
}
export default Display
import React from 'react'
const Button: React.SFC = () => {
return (
<div>
<button>add!</button>
</div>
)
}
export default Button
import React from 'react';
import Display from './components/Display';
import Button from './components/Button';
const App: React.FC = () => {
return (
<div>
<Display />
<Button />
</div>
);
}
export default App;
unstatedの導入
**unstatedは、コンポーネントの状態(state)の部分と見た目の部分を引き剥がすだけです。**なので、簡単に導入できます。
従来のコンポーネントは、一つのファイルで、状態(state)の管理と見た目の作成を全てを担っていました。
これだと、状態を他のコンポーネントに再利用できなくて、どうしても他のコンポーネントに状態を渡したいときは、props経由で状態(state)を渡します。ただ、コンポーネントの構造が複雑になってくると、propsで状態を渡すのがだるくなってきます。しかも、propsは親から子には渡せますが、子から親には渡せないので、開発を進めていると途中で詰むことがあります。
一方で、unstatedは、見た目の部分と状態の部分に分けます。状態の部分を、コンテナと呼びます。
unstatedは、親子関係なしに状態(state)を渡すことができます。
では、実際にunstatedを導入してみます。
$ npm install unstated
$ npm install
unstatedを使うためには、Providerで囲む必要があります。
import React from 'react'
import Display from './components/Display'
import Button from './components/Button'
import { Provider } from 'unstated'
const App: React.FC = () => {
return (
<Provider>
<div>
<Display />
<Button />
</div>
</Provider>
);
}
export default App;
containerを作ります。src直下にcontainersフォルダを作り、その中にCountContainer.tsを作ります。
src-
|-containers
| |-CountContainer.ts
|
|-components
|-Display.tsx
|-Button.tsx
import { Container } from 'unstated'
interface IState {
count: number
}
export default class CountContainer extends Container<IState> {
public constructor() {
super()
this.state = {
count: 0
}
this.addCount = this.addCount.bind(this)
}
public addCount() {
this.setState({
count: this.state.count + 1
})
}
}
containerにあるstateをDisplay.tsxに渡します。
import React from 'react'
import { Subscribe } from 'unstated'
import CountContainer from '../containers/CountContainer';
const Display: React.SFC = () => (
<Subscribe to={[CountContainer]}>
{(cCount: CountContainer) => {
return (
<div>
<h1>{cCount.state.count}</h1>
</div>
)
}}
</Subscribe>
)
export default Display
containerにあるaddCountという関数をButton.tsxに渡します。
import React from 'react'
import { Subscribe } from 'unstated'
import CountContainer from '../containers/CountContainer';
const Button: React.SFC = () => (
<Subscribe to={[CountContainer]}>
{(cCount: CountContainer) => {
return (
<div>
<button onClick={cCount.addCount}>add!</button>
</div>
)
}}
</Subscribe>
)
export default Button
addボタンを押すと、カウントが増えていきます。