はじめに
この資料は9/27のJoolen社内勉強会に使用する予定の資料です
告知!
10月2日(水)に、松戸駅近くでLaravel6.0のドキュメント(英文)をみんなで読もう! #1やります。よかったらきてください。
まずは
ライオンズファンのエンジニアとして、この気持ちを技術で社内共有したい!
Reactの入門情報も合わせて伝えたら最高ではないか!
と言うわけで、Reactについての簡単な説明
- facebook製のOSS。
- MVCで言う所のV(View)を司っている
- Javascriptで書かれている
- コンポーネント指向(小さなパーツの集まりで一つのページを構成する)
コンポーネント指向は個人的にはレゴブロックで理解しています。
ブロック = 小さなコンポーネント
完成物 = アプリケーションのページ
Typescriptとは
- マイクロソフトによって開発され、メンテナンスされているフリーでオープンソースのプログラミング言語
- Visual Studio Codeとの相性が半端じゃなく良い。
- 型定義ファイルをサポートしており、既存のJavaScriptライブラリに型情報を付与して利用できる。今までのJavascriptの変数にどんな型が入ってくるか分からない問題を根本から解決してくれる。
- 実際に動かすにはトランスパイルが必要。
- 既存のパッケージに型ファイルがない時には自分で作らなきゃいけない等、辛みもあるけれど、品質を保ちながら開発するには、かなり役立つ。
早速、作ってみる
create-react-app
を使ってReactの空プロジェクトを生成しても良いですが、JoolenのReactボイラーテンプレートがあるのでこれを利用
Node.js
とgit
はあらかじめインストールしておいてくださいね!
# gitからボイラーテンプレートをClone
git clone https://github.com/joolen/react-project-template.git renpa-lions
# ディレクトリを移動して
cd renpa-lions/
# 関連するパッケージをインストール(たくさんあるので、時間がかかる)
npm install
# npm start で起動
npm start
それだけで、ローカルへのReactの導入は完了です。この画面がhttp://localhost:3000/
で出ればOK!
Lionsを讃えるための機能は以下の通りです。
入門編なので、あまり作り込みはしないように簡単な機能を作ります。
まずはタイムライン機能から
タイムライン機能を表示するためのコンポーネントが既に存在しているので、それをインストール。
npm install --save react-twitter-widgets
西武ライオンズの公式ツイッターアカウント名をパラメータにした表示用機能を作成
import React from 'react';
import { Timeline as TL } from 'react-twitter-widgets'/*ここで必要なパッケージをインポート */
/**
* Twitterのタイムラインを表示するコンポーネントをここで定義
*/
export const Timeline = () => {
return (
<TL dataSource={{
sourceType: 'profile',
screenName: 'lions_official'
}}
options={{
username: 'lions_official',
height: '600'
}}
onLoad={() => console.log('Timeline is loaded!')} />
)
}
これだけで、タイムライン機能は出来上がりです。
コンポーネント指向の強さ
すでに開発済みのコンポーネントが世の中にはたくさんありますし(もちろん、選定は必要)、自作のコンポーネントを様々なページに流用することが可能です。
車輪の再発明を予防し、DRY(Don't Repeat Yourself)の法則を守りやすい作りができます。
次は特徴的な選手の決め台詞を表示します。
ソースコードはこんな感じになりました。
import React, { useState, useCallback } from 'react';
import { Button } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import Card from '@material-ui/core/Card';
import CardActionArea from '@material-ui/core/CardActionArea';
import CardContent from '@material-ui/core/CardContent';
import CardMedia from '@material-ui/core/CardMedia';
import Typography from '@material-ui/core/Typography';
/**
* ここで表示する情報の幅や高さを指定しています。
*/
const useStyles = makeStyles({
card: {
maxWidth: 345,
},
media: {
height: 320,
},
});
export const SignaturePhrase = () => {
const classes = useStyles();
/**
* ここに初期値をセットします。ReactHooks定義
*/
const [player, setPlayer] = useState({
imageUrl: 'https://www.seibulions.jp/pc/_pl_img/old/company/img/img_2016petmark01.jpg',
name: '決めゼリフ!',
signiturePhrase: 'ここに出ます'
});
/**
* ボタンが押された時の挙動
*/
const setPhrase = useCallback(() => {//useCallbackを入れることで、無駄な関数の再生性を防ぎます。
const target = getRandomInt(players.length);//誰が出るかはお楽しみ。
setPlayer({
imageUrl: players[target].imageUrl,
name: players[target].name,
signiturePhrase: players[target].sighniturePhrase
})//React Hooks発動!ここで塗り替えられたStateは即座にページに反映されます。
}, []);
return (
<div>
<Button size='large' color='primary' variant='contained' onClick={setPhrase}>決め台詞を聞く!</Button>
<Card className={classes.card}>
<CardActionArea>
<CardMedia
className={classes.media}
image={player.imageUrl}
title="Logo"
/>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
{player.name}
</Typography>
<Typography variant="h6" color="textSecondary" component="p">
{player.signiturePhrase}
</Typography>
</CardContent>
</CardActionArea>
</Card>
</div>
)
}
/**
* データベース代わり。ここのデータを引っ張ってきています。
*/
const players = [
{ imageUrl: 'https://www.seibulions.jp/cmn/images/player/2019/ph_player_99.jpg', name: '#99 エルネスト・メヒア', sighniturePhrase: 'メヒアさまさまやー' },
{ imageUrl: 'https://www.seibulions.jp/cmn/images/player/2019/ph_player_5.jpg', name: '#5 外崎 修汰', sighniturePhrase: 'アップルパーンチ!' },
{ imageUrl: 'https://www.seibulions.jp/cmn/images/player/2019/ph_player_54.jpg', name: '#54 ザック・ニール', sighniturePhrase: 'あざーす!' },
{ imageUrl: 'https://www.seibulions.jp/cmn/images/player/2019/ph_player_33.jpg', name: '#33 山川 穂高', sighniturePhrase: 'どすこーい!' },
{ imageUrl: 'https://www.seibulions.jp/cmn/images/player/2019/ph_player_10.jpg', name: '#10 森 友哉', sighniturePhrase: '吉田打った?' },
]
function getRandomInt(max: number) {
return Math.floor(Math.random() * Math.floor(max));
}
ここでは特にmaterial-ui
以外のライブラリは使わずに自分自身で書いています。
React Hooksによりコンポーネント内の処理をかなり
シンプルに書けるようになったと思います。
あとは表示したいページにコンポーネントを埋め込んであげるだけ
import React from 'react';
import Typography from '@material-ui/core/Typography';
import Container from '@material-ui/core/Container';
import { Grid } from '@material-ui/core';
import { Timeline } from '../organisms/Timeline';
import { SignaturePhrase } from '../organisms/SignaturePhrase';
export const WelcomeTemplate = () => {
return (
<Container maxWidth="lg">
<Grid container spacing={3}>
<Grid item container justify='center'>
<Typography variant="h4" component="div" >
埼玉西武ライオンズ連覇おめでとうございます!
</Typography>
<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154110/727b2a0b-f5a9-9f2d-9dad-8bc5e192ed5c.jpeg'
style={{ height: 300 }} />
</Grid>
<Grid item md={5}>
<Timeline /> {/* ここにTwitterのタイムライン機能を埋め込み */}
</Grid>
<Grid item md={7}>
<SignaturePhrase /> {/*ここは決め台詞を取得するところ */}
</Grid>
</Grid>
</Container>
)
}
コンポーネントの開発を助けてくれるスペシャルなツール
Storybookというツールがあります。自分好みのコンポーネントのカタログを作ることができるので、非常に重宝しますよ!