- 投稿日:2019-07-08T19:50:18+09:00
React hooksこんな風に使ってみたよ
バイトでReactを使うことになり、hooksの利用を
強行提案して書いて見たところ、楽しすぎたのでどんな感じで使っているかを紹介したい。あくまでこんな感じで使ってみたよって話なので、良いプラクティスかどうかは自己判断でお願いします
そもそもなんでhooksを利用するのか
公式ドキュメントから引用すれば
ステートフルなロジックをコンポーネント間で再利用する
ためです。今まではHoCとかで管理してたものをhooksでやりやすくした感じですね。
例1) 初期化するときの非同期通信の共通化
まずは単純にuseEffect(あるいはcomponentDidMount)内のfetchしてjsonにしてみたいなロジックを一箇所にまとめてみる
useInitFetch.jsimport { useEffect } from 'react'; export function useInitFetch(path, callback) { useEffect(() => { fetch(`http://path/to/api/${path}`) .then(res => res.json()) .then(res => ({data: res}), e => ({error: e})) .then(res => callback(res)); }, []); }使い方は
MyComponent.jsximport React, { useState } from 'react'; import { useInitFetch } from './useInitFetch' export const MyComponent = () => { const [value, setValue] = useState({}); useInitFetch('path/to/value', (res) => setValue(res)); return <div>{value}</div> }例2) socket.ioの通信をどのコンポーネントからも呼び出せるようにする
useSocketはこんなことができるようにしました
- いろんなところからsocket.emitを呼び出したいが、socket自体はコンポーネントの表現には関わらないので、バケツリレーを避けたい -> context apiを利用
- 間違ってio.connectをなんども呼び出さないようにしたい -> 同じくcontext apiで解決可能
- あるコンポーネントがマウントするまでイベントを登録したくない・アンマウント後はイベントを削除したい -> useEffectのクリーンアップを利用
useSocket.jsximport React, { useContext, useEffect, useState, createContext } from 'react'; import io from 'socket.io-client'; export const socketContext = createContext(); export const SocketProvider = ({children}) => { const [socket, _] = useState(() => io.connect('http://path/to/socketapi')); useEffect(() => { return function cleanup() { socket.close(); } }, []); return ( <socketContext.Provider value={socket}> {children} </socketContext.Provider> ) } export const useSocket = (setEvent, removeEvent) => { const socket = useContext(socketContext); useEffect(() => { setEvent(socket); return () => { removeEvent(socket); } }, []); return socket; }使い方:
MyComponent.jsximport React, { useState } from 'react'; import { SocketProvider, useSocket } from './useSocket'; export const MyComponent = () => { const [value, setValue] = useState({}); const socket = useSocket((socket) => { socket.on('myevent', (res) => { setValue(res); }); }, (socket) => { socket.off('myevent'); }); return ( <> {value} <button onClick={() => socket.emit('myevent2', 'hoge')>Click!</button> </> ) export const App = () => { return ( <SocketProvider> <MyComponent /> </SocketProvider> }これに限ったことではないですが、hooks + context APIは特にグローバルに唯一存在してほしい変数がある時にとても強力であると感じました
例3) 別Windowで開く&別Windowは最大1つまで
同じくcontext api + hooksを利用できます。
useNewWindow.jsximport { useState, createContext } from 'react'; export const windowContext = createContext(); export const WindowProvider = ({children}) => { const [win, setWin] = useState(null); return ( <windowContext.Provider value={[win, setWin]}> {children} </windowContext.Provider> ) } export const useNewWindow = (title, features) => { const [win, setWin] = useContext(windowContext); return (url) => { if(win === null || win.isClosed) { setWin(window.open(url, title, features)); } } }使い方:
MyComponent.jsximport React, { useState } from 'react'; import { WindowProvider, useNewWindow } from './useNewWindow'; export const MyComponent = () => { const openWindow = useNewWindow('HogeTitle', 'resizable=yes,scrollbars=yes'); return ( <button onClick={() => openWindow('path/to/newWindow')}>Open Window</button> ) export const App = () => { return ( <WindowProvider> <MyComponent /> </WindowProvider> ) }; }まとめ
なんかhooksがいいっていうよりcontext apiがいいみたいな記事になってしもうた
useRefとかuseMemoとかまだまだ面白そうな機能がいっぱいなので、使う場面があったら更新していきます
- 投稿日:2019-07-08T19:40:02+09:00
【備忘録】React & TypeScript & Webpack4 & Babel7 & dev-server の最小構成ボイラープレートの作成 -画像ファイル読み込み設定-
【備忘録】React & TypeScript & Webpack4 & Babel7 & dev-server の最小構成ボイラープレートの作成 -画像ファイル読み込み設定-
前回の記事 で作成したボイラープレートに画像の読み込み設定を実装する。
使用するnpmモジュール
今回使用するモジュールは以下の通り。(使用するモジュールはすべてlatest)
モジュール名 バージョン 説明 url-loader 2.0.1 画像ファイル読み込みに必要 画像ファイルの読み込み用モジュールはurl-loaderとfile-loaderがあるが、指定したファイルのみを読み込むfile-loaderよりもurl-loaderの方がシンプルに実装できるので今回は、url-loaderを使用。(用途によって使い分け)
package.jsonへのモジュール追加とインストール
使用するnpmモジュールをpackage.jsonに追加する。
{ "name": "react-ts-webpack", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "start": "webpack-dev-server --open", "build": "webpack", "build-prod": "webpack --mode=production" }, "keywords": [], "author": "kento75 <kento2github@gmail.com> (https://overreact.tk)", "license": "ISC", "dependencies": { "@babel/core": "^7.4.5", "@babel/preset-env": "^7.4.5", "@babel/preset-react": "^7.0.0", "@babel/preset-typescript": "^7.3.3", "@types/react": "^16.8.22", "@types/react-dom": "^16.8.4", "autoprefixer": "^9.6.1", "babel-loader": "^8.0.6", "css-loader": "^3.0.0", "node-sass": "^4.12.0", "postcss-loader": "^3.0.0", "react": "^16.8.6", "react-dom": "^16.8.6", "sass-loader": "^7.1.0", "style-loader": "^0.23.1", "url-loader": "^2.0.1", "webpack": "^4.35.0", "webpack-cli": "^3.3.5" }, "devDependencies": { "webpack-dev-server": "^3.7.2" } }追加後、以下のコマンドを実行してnpmモジュールをインストールする。
$ npm installwebpack.config.jsファイルに設定追加
web pack.config.jsファイルにファイル読み込み用の設定を追加する。
また、前回css-loaderに設定した
url: false
をcss側からのファイル読み込みを行えるようにurl: true
に修正する。const path = require ('path'); const rules = [ /* TypeScript用の設定 */ { // 対象とする拡張子を指定 test: /\.tsx?/, // 対象から外すディレクトリを指定 exclude: /node_modules/, // babelを使用する loader: 'babel-loader', }, /* Sass用設定 */ { // 対象とする拡張子を指定 test: /\.scss$/, use: [ // linkタグへの出力用 'style-loader', // CSSのバンドル設定 { loader: 'css-loader', options: { /////////////// ここをtrueに変更 /////////////// // css内のurl()メソッドを取り込む設定 url: true, // // ソースマップの有効化 development と production で勝手に切り替わるのでコメントアウト // sourceMap: true, // sass-loader と postcss-loader を使用するので 2 を設定 // ここを参考に設定 https://github.com/webpack-contrib/css-loader#importloaders importLoaders: 2, }, }, 'postcss-loader', { loader: 'sass-loader', // options: { // // ソースマップの有効化 development と production で勝手に切り替わるのでコメントアウト // sourceMap: true, // } }, ], }, ///// ここから追加 ///// /* 画像ファイル用設定 */ { // 対象となるファイルの拡張子を設定 test: /\.(gif|png|jpg|jpeg|svg|ttf|eot|wof|woff|woff2)$/, // 画像をBase64で取り込み loader: 'url-loader', }, ///// ここまで追加 ///// ]; module.exports = { // ブラウザ環境で使用するためwebをtargetとする target: 'web', // モード値を production に設定すると最適化された状態で、 // development に設定するとソースマップ有効でJSファイルが出力される mode: 'development', // 起点となるTSXファイル(エントリーポイント) entry: './src/index.tsx', // ビルド後の出力先設定 output: { // 出力先パス path: path.resolve (__dirname, 'build'), // ファイル名 filename: 'bundle.js', }, module: { // ビルド時に使用するルール(上で設定)を設定 rules, }, resolve: { // 対象とする拡張子を指定 extensions: ['.ts', '.tsx', '.js'], }, // webpack-dev-serverの設定 devServer: { // 起点となるパス contentBase: './', // ポート番号 port: 5000, }, };ここまでの設定で使用する準備は完了。
動作確認
動作を確認するためにindex.tsxでimageファイルを読み込む修正を行う。
あらかじめ、読み込み画像ファイルを
<プロジェクトルート>src/assets/
の下に配置しておく。import React from 'react'; import ReactDOM from 'react-dom'; import './scss-style.scss'; // import でもできるが面倒なので、妥協して require を使用 const reactImg = require('./assets/img/react.png'); function App(): JSX.Element { const sum = (a: number, b: number): number => a + b; return ( <React.Fragment> <div> <h1>React & TypeScript!</h1> <p>Test: {sum(15, 15)} </p> </div> <div className="scss-style" /> <div className="sass-img" /> <div> <img src={reactImg} alt="react" /> </div> </React.Fragment> ); } export default App; const root = document.getElementById('app-root'); ReactDOM.render(<App />, root);Sassファイルからも読み込みができることを確認するため、scss-style.scssを修正する。
.scss-style { background: #e47474; height: 15px; // ベンダープレフィックス確認用に適当に入れただけ transform: scale(2); } // Sassから画像を読み込む .sass-img { height: 400px; padding: 0; margin: 0; background: url("./assets/img/vue.png") no-repeat; }実装が完了したら、以下のコマンドを実行して開発用サーバー起動することを確認する。
$ npm start > react-ts-webpack@1.0.0 start /Users/kento/Programing/VScodeProjects/ts-react-sass-simple-boiler-v2 > webpack-dev-server --open ℹ 「wds」: Project is running at http://localhost:5000/ ℹ 「wds」: webpack output is served from / ℹ 「wds」: Content not from webpack is served from ./ ℹ 「wdm」: wait until bundle finished: / ℹ 「wdm」: Hash: 8f73de6147b59cb9288f Version: webpack 4.35.0 Time: 2220ms Built at: 2019-07-08 19:20:38 Asset Size Chunks Chunk Names bundle.js 1.29 MiB main [emitted] main Entrypoint main = bundle.js [0] multi (webpack)-dev-server/client?http://localhost:5000 ./src/index.tsx 40 bytes {main} [built] [./node_modules/react-dom/index.js] 1.33 KiB {main} [built] [./node_modules/react/index.js] 190 bytes {main} [built] [./node_modules/webpack-dev-server/client/index.js?http://localhost:5000] (webpack)-dev-server/client?http://localhost:5000 4.29 KiB {main} [built] [./node_modules/webpack-dev-server/client/overlay.js] (webpack)-dev-server/client/overlay.js 3.51 KiB {main} [built] [./node_modules/webpack-dev-server/client/socket.js] (webpack)-dev-server/client/socket.js 1.53 KiB {main} [built] [./node_modules/webpack-dev-server/client/utils/createSocketUrl.js] (webpack)-dev-server/client/utils/createSocketUrl.js 2.77 KiB {main} [built] [./node_modules/webpack-dev-server/client/utils/log.js] (webpack)-dev-server/client/utils/log.js 964 bytes {main} [built] [./node_modules/webpack-dev-server/client/utils/reloadApp.js] (webpack)-dev-server/client/utils/reloadApp.js 1.63 KiB {main} [built] [./node_modules/webpack-dev-server/client/utils/sendMessage.js] (webpack)-dev-server/client/utils/sendMessage.js 402 bytes {main} [built] [./node_modules/webpack-dev-server/node_modules/strip-ansi/index.js] (webpack)-dev-server/node_modules/strip-ansi/index.js 161 bytes {main} [built] [./node_modules/webpack/hot sync ^\.\/log$] (webpack)/hot sync nonrecursive ^\.\/log$ 170 bytes {main} [built] [./src/assets/img/react.png] 31.3 KiB {main} [built] [./src/index.tsx] 810 bytes {main} [built] [./src/scss-style.scss] 1.35 KiB {main} [built] + 37 hidden modules ℹ 「wdm」: Compiled successfully.起動後、localhost:5000 にアクセスする。
画像ファイルが表示されること。画像ファイルのパスを確認。
以上で確認完了。
作成したボイラープレートは こちら
- 投稿日:2019-07-08T19:40:02+09:00
【備忘録③】React & TypeScript & Webpack4 & Babel7 & dev-server の最小構成ボイラープレートの作成 -画像ファイル読み込み設定-
【備忘録】React & TypeScript & Webpack4 & Babel7 & dev-server の最小構成ボイラープレートの作成 -画像ファイル読み込み設定-
前回の記事 で作成したボイラープレートに画像の読み込み設定を実装する。
使用するnpmモジュール
今回使用するモジュールは以下の通り。(使用するモジュールはすべてlatest)
モジュール名 バージョン 説明 url-loader 2.0.1 画像ファイル読み込みに必要 画像ファイルの読み込み用モジュールはurl-loaderとfile-loaderがあるが、指定したファイルのみを読み込むfile-loaderよりもurl-loaderの方がシンプルに実装できるので今回は、url-loaderを使用。(用途によって使い分け)
package.jsonへのモジュール追加とインストール
使用するnpmモジュールをpackage.jsonに追加する。
{ "name": "react-ts-webpack", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "start": "webpack-dev-server --open", "build": "webpack", "build-prod": "webpack --mode=production" }, "keywords": [], "author": "kento75 <kento2github@gmail.com> (https://overreact.tk)", "license": "ISC", "dependencies": { "@babel/core": "^7.4.5", "@babel/preset-env": "^7.4.5", "@babel/preset-react": "^7.0.0", "@babel/preset-typescript": "^7.3.3", "@types/react": "^16.8.22", "@types/react-dom": "^16.8.4", "autoprefixer": "^9.6.1", "babel-loader": "^8.0.6", "css-loader": "^3.0.0", "node-sass": "^4.12.0", "postcss-loader": "^3.0.0", "react": "^16.8.6", "react-dom": "^16.8.6", "sass-loader": "^7.1.0", "style-loader": "^0.23.1", "url-loader": "^2.0.1", "webpack": "^4.35.0", "webpack-cli": "^3.3.5" }, "devDependencies": { "webpack-dev-server": "^3.7.2" } }追加後、以下のコマンドを実行してnpmモジュールをインストールする。
$ npm installwebpack.config.jsファイルに設定追加
web pack.config.jsファイルにファイル読み込み用の設定を追加する。
また、前回css-loaderに設定した
url: false
をcss側からのファイル読み込みを行えるようにurl: true
に修正する。const path = require ('path'); const rules = [ /* TypeScript用の設定 */ { // 対象とする拡張子を指定 test: /\.tsx?/, // 対象から外すディレクトリを指定 exclude: /node_modules/, // babelを使用する loader: 'babel-loader', }, /* Sass用設定 */ { // 対象とする拡張子を指定 test: /\.scss$/, use: [ // linkタグへの出力用 'style-loader', // CSSのバンドル設定 { loader: 'css-loader', options: { /////////////// ここをtrueに変更 /////////////// // css内のurl()メソッドを取り込む設定 url: true, // // ソースマップの有効化 development と production で勝手に切り替わるのでコメントアウト // sourceMap: true, // sass-loader と postcss-loader を使用するので 2 を設定 // ここを参考に設定 https://github.com/webpack-contrib/css-loader#importloaders importLoaders: 2, }, }, 'postcss-loader', { loader: 'sass-loader', // options: { // // ソースマップの有効化 development と production で勝手に切り替わるのでコメントアウト // sourceMap: true, // } }, ], }, ///// ここから追加 ///// /* 画像ファイル用設定 */ { // 対象となるファイルの拡張子を設定 test: /\.(gif|png|jpg|jpeg|svg|ttf|eot|wof|woff|woff2)$/, // 画像をBase64で取り込み loader: 'url-loader', }, ///// ここまで追加 ///// ]; module.exports = { // ブラウザ環境で使用するためwebをtargetとする target: 'web', // モード値を production に設定すると最適化された状態で、 // development に設定するとソースマップ有効でJSファイルが出力される mode: 'development', // 起点となるTSXファイル(エントリーポイント) entry: './src/index.tsx', // ビルド後の出力先設定 output: { // 出力先パス path: path.resolve (__dirname, 'build'), // ファイル名 filename: 'bundle.js', }, module: { // ビルド時に使用するルール(上で設定)を設定 rules, }, resolve: { // 対象とする拡張子を指定 extensions: ['.ts', '.tsx', '.js'], }, // webpack-dev-serverの設定 devServer: { // 起点となるパス contentBase: './', // ポート番号 port: 5000, }, };ここまでの設定で使用する準備は完了。
動作確認
動作を確認するためにindex.tsxでimageファイルを読み込む修正を行う。
あらかじめ、読み込み画像ファイルを
<プロジェクトルート>src/assets/
の下に配置しておく。import React from 'react'; import ReactDOM from 'react-dom'; import './scss-style.scss'; // import でもできるが面倒なので、妥協して require を使用 const reactImg = require('./assets/img/react.png'); function App(): JSX.Element { const sum = (a: number, b: number): number => a + b; return ( <React.Fragment> <div> <h1>React & TypeScript!</h1> <p>Test: {sum(15, 15)} </p> </div> <div className="scss-style" /> <div className="sass-img" /> <div> <img src={reactImg} alt="react" /> </div> </React.Fragment> ); } export default App; const root = document.getElementById('app-root'); ReactDOM.render(<App />, root);Sassファイルからも読み込みができることを確認するため、scss-style.scssを修正する。
.scss-style { background: #e47474; height: 15px; // ベンダープレフィックス確認用に適当に入れただけ transform: scale(2); } // Sassから画像を読み込む .sass-img { height: 400px; padding: 0; margin: 0; background: url("./assets/img/vue.png") no-repeat; }実装が完了したら、以下のコマンドを実行して開発用サーバー起動することを確認する。
$ npm start > react-ts-webpack@1.0.0 start /Users/kento/Programing/VScodeProjects/ts-react-sass-simple-boiler-v2 > webpack-dev-server --open ℹ 「wds」: Project is running at http://localhost:5000/ ℹ 「wds」: webpack output is served from / ℹ 「wds」: Content not from webpack is served from ./ ℹ 「wdm」: wait until bundle finished: / ℹ 「wdm」: Hash: 8f73de6147b59cb9288f Version: webpack 4.35.0 Time: 2220ms Built at: 2019-07-08 19:20:38 Asset Size Chunks Chunk Names bundle.js 1.29 MiB main [emitted] main Entrypoint main = bundle.js [0] multi (webpack)-dev-server/client?http://localhost:5000 ./src/index.tsx 40 bytes {main} [built] [./node_modules/react-dom/index.js] 1.33 KiB {main} [built] [./node_modules/react/index.js] 190 bytes {main} [built] [./node_modules/webpack-dev-server/client/index.js?http://localhost:5000] (webpack)-dev-server/client?http://localhost:5000 4.29 KiB {main} [built] [./node_modules/webpack-dev-server/client/overlay.js] (webpack)-dev-server/client/overlay.js 3.51 KiB {main} [built] [./node_modules/webpack-dev-server/client/socket.js] (webpack)-dev-server/client/socket.js 1.53 KiB {main} [built] [./node_modules/webpack-dev-server/client/utils/createSocketUrl.js] (webpack)-dev-server/client/utils/createSocketUrl.js 2.77 KiB {main} [built] [./node_modules/webpack-dev-server/client/utils/log.js] (webpack)-dev-server/client/utils/log.js 964 bytes {main} [built] [./node_modules/webpack-dev-server/client/utils/reloadApp.js] (webpack)-dev-server/client/utils/reloadApp.js 1.63 KiB {main} [built] [./node_modules/webpack-dev-server/client/utils/sendMessage.js] (webpack)-dev-server/client/utils/sendMessage.js 402 bytes {main} [built] [./node_modules/webpack-dev-server/node_modules/strip-ansi/index.js] (webpack)-dev-server/node_modules/strip-ansi/index.js 161 bytes {main} [built] [./node_modules/webpack/hot sync ^\.\/log$] (webpack)/hot sync nonrecursive ^\.\/log$ 170 bytes {main} [built] [./src/assets/img/react.png] 31.3 KiB {main} [built] [./src/index.tsx] 810 bytes {main} [built] [./src/scss-style.scss] 1.35 KiB {main} [built] + 37 hidden modules ℹ 「wdm」: Compiled successfully.起動後、localhost:5000 にアクセスする。
画像ファイルが表示されること。画像ファイルのパスを確認。
以上で確認完了。
作成したボイラープレートは こちら
- 投稿日:2019-07-08T19:05:42+09:00
reactのコードの整形を自分でしてるの?! 面倒なコード整形を自動化したいあなたのためのprettier入門
動機
割愛
prettierとは?
割愛
早速使ってみよう!!
prettierのinstall
yarn add prettier or npm install prettierこれでprettierのコマンドが使えるようになります!!
(もしかしたら、パスを通す必要があるかも。下記のprettierのコマンドでエラーが出たら、この記事にコメント!!)prettierの実行
prettier [opts] [filename ...]とすると、ファイルを整形してくれたり、整形できてないところのチェックをしてくれます!
exapleprettier --wire App.js →App.jsファイルを自動整形してくれます! prettier --check App.js →App.jsファイルでおかしなコードがあるところを教えてくれます!
prettier --wire App.jsの例文
<SimpleSlider>の箇所が変わっています!!
インデントが7個くらいあるとこを2個に変更してくれました!!(めちゃ嬉しい)App.jsimport React from "react"; import Test from "./components/Test"; import SimpleSlider from "./components/SimpleSlider"; import "./App.css"; function App() { return ( // この配下にrootコンポーネントを書いていく <SimpleSlider /> ); } export default App; ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ import React from "react"; import Test from "./components/Test"; import SimpleSlider from "./components/SimpleSlider"; import "./App.css"; function App() { return ( // この配下にrootコンポーネントを書いていく <SimpleSlider /> ); } export default App;けどさ、毎回prettierコマンド打つのだるくない?yarnでやってるんやけ、yarnコマンド使いたくない??
はい。yarn devやyarn start等のコマンドを皆さんも打ってますよね?
そっちの方がスタイリッシュで格好よくないですか?
yarnコマンドの設定に関しては、package.jsonのscriptsの箇所の役割です!
このセクションでは、package.jsonを少し見てみましょう!!"yarn run fmt"でprettierの自動整形を行う
まずは、Qiitaの記事を参考にして、上記のコマンドでprettierを使えるようにしましょう!!
何事も小さいところから少しずつ試すことが大事です。ブリボンのreact練習ディレクトリ"scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject", "fmt": "prettier --write \"src/App.js\"" →→→ ここのところがprettierのコマンドのところ!! },scriptsの"fmt"の箇所を上記のようにします!
すると、App.jsファイルのみ、prettierで自動成形されます!!ブリボンあほか?App.jsファイルだけ整形しても意味ないやん
はい。すみません。
全ファイルを自動整形しないと意味ないですよね。。
下記のようにscriptsの箇所を変更ください。"scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject", "fmt": "prettier --write \"src/**/*.js\"" },さらなる高みへ!VSCodeでsave時にprettierを走らせる!
やることは二つです。
一つ目はプラグインでPrettier Pluginのインストール
二つ目はVSCodeのsettings.jsonで下記のコマンドを追加"editor.formatOnSave": trueあとがき
ブリボンは、タスクで初めて使うパッケージを導入する時、自分のローカル環境を使います。
practice-reactというプロジェクトを立ち上げて、そこにパッケージをインストールして遊んでいます。
今回のprettierも例外ではなく、自分のローカルを爆速で開発できるようにすること、prettierのお勉強をすること、以上2点の目的により、ローカル環境をいじってみました!!随時変更・追加していきます!!
(6/9日曜に作成)
(6/9日曜に修正)参考文献
- 投稿日:2019-07-08T19:02:51+09:00
コードのチェックはESLintに任せよう! ブリボンの初めてのESLint
作成趣旨
前回、prettierでコードの自動整形を試してみたブリボン。
prettierのQiita記事はこちら
ESLintと組み合わせれば、もっと自動にコードの整形をしてくれるぞ!という情報を得まして、早速練習用リポジトリでESLintを導入してみました。ESLintとは?
・JavaScriptの構文チェッカー
・細かな設定をすることができる要は、変なコードを書いていないか( ; 忘れや import ミスなど)を教えてくれる便利なやつです。
prettierと組み合わせると、変なコードを自動認識した上で、コードの整形までやってくれます。早速使ってみよう!!
yarn add ESLinteslint --initをターミナルで呼び出すことで、対話的にeslintの設定ファイルを作ってくれるらしいです。
今回は、Qiitaの記事を元にファイルを生成しました。eslintrc.json{ "extends": ["eslint:recommended"], "plugins": [], "parserOptions": {}, "env": { "browser": true}, "globals": {}, "rules": {} }まずは、こんな感じで簡単に作ってみましょう!!
参考: ESLint 最初の一歩eslint コマンドを使おう!
eslint src/App.js上記のコマンドで、src配下のApp.jsファイルの構文チェックができる。
yarn lintでESLintを使う
package.json"lint": "eslint src/**/*.js"上記でsrc配下の全ファイルが、ESLintによりふるいにかけられます。
以下余談です
やったこと
yarn add eslint-plugin-prettier yarn add eslint-plugin-react解決したエラー
Parsing error: Unexpected token <
解決方法
yarn add babel-eslinteslintrc.json{ "parser": "babel-eslint", }yarn startできない
"babel-eslint": "10.0.1", "eslint": "^5.16.0",上記のバージョンを使用する
関数コンポーネントで React を使っていなくても、宣言しないと使えないのに、明示的に使っていないという理由で、エラーを吐きだす。
yarn add eslint-plugin-reacteslintrc.json"extends": ["eslint:recommended", "plugin:react/recommended"],参考文献
ESLint 最初の一歩
ESlint rules
ESLintで構文チェック(Webpack)
JSプログラマーのイラッとする「クセ」はESLintを導入して対処しよう
- 投稿日:2019-07-08T17:02:01+09:00
react-routerに入門する
数か月前にreact-routerとReduxを同時に学ぼうとして挫折したので、今回はまず順を追ってreact-routerを学習する。
インストールするもの
vueのときと同じかな? と最初に何も考えずにreact-routerを入れたのですが、調べるとどうやらこれはコアの部分。
ウェブアプリケーションを構築する為に必要なのは「react-router-dom」の方でした(こちらを入れるとreact-routerも一緒に入ってくれます)。今回は
react-router-dom 5.0.1
を使用しています。まずはApp.jsにざらっと書いてみる
index.jsimport React from 'react' import ReactDOM from 'react-dom' import './styles.scss' import App from './App' ReactDOM.render( <App />, document.getElementById('root') )App.jsimport React, { Component } from 'react' import { BrowserRouter, Route, Link } from 'react-router-dom' const App = () => ( <BrowserRouter> <h1>react-routerに入門する。</h1> <nav> <ul> <li><Link to='/'>Index</Link></li> <li><Link to='/second'>Second</Link></li> <li><Link to='/third'>Third</Link></li> </ul> </nav> <article> <Route exact path='/' component={Index} /> <Route path='/second' component={Second} /> <Route path='/third' component={Third} /> </article> </BrowserRouter> ) const Index = () => ( <div> <h2>Index</h2> <p>インデックスページ</p> </div> ) const Second = () => ( <div> <h2>Second</h2> <p>二番目のページです</p> </div> ) const Third = () => ( <div> <h2>Third</h2> <p>三番目のページです</p> </div> ) export default Appリンクは
<Link to='/'>
で書き、<Route />
でルーティングを設定すれば良いので、ここまではVueのときと然程遠くない感覚で書けました。
(色々な方の記事を見ていると、BrowserRouterにasで「Router」と付けている人が多いみたいだったんですが何故だろう……)ページごとにファイルを分けたい
といってもこれは単に分けるだけ。
pages/Index.jsimport React, { Component } from 'react' const Index = () => ( <div> <h2>Index</h2> <p>二番目のページです</p> </div> ) export default Index他ページも同様に。
App.jsimport React, { Component } from 'react' import { BrowserRouter, Route, Link } from 'react-router-dom' import Index from './pages/Index' import Second from './pages/Second' import Third from './pages/Third' const App = () => ( <BrowserRouter> <h1>react-routerに入門する。</h1> <nav> <ul> <li><Link to='/'>Index</Link></li> <li><Link to='/second'>Second</Link></li> <li><Link to='/third'>Third</Link></li> </ul> </nav> <article> <Route exact path='/' component={Index} /> <Route path='/second' component={Second} /> <Route path='/third' component={Third} /> </article> </BrowserRouter> ) export default App動的ルートマッチングしたい
したい。
今回はSecondの下層ページとして実装します。
まずは中身から。pages/SecondChild.jsimport React, { Component } from 'react' const SecondChild = (props) => { const { id } = props.match.params return ( <div> <h2>SecondChild</h2> <p>{id}のページです</p> </div> ) } export default SecondChild次いでApp.jsを書いていくんですが……。
以下、失敗例です(´・ω・`)。App.jsimport React, { Component } from 'react' import { BrowserRouter, Route, Link } from 'react-router-dom' import Index from './pages/Index' import Second from './pages/Second' import SecondChild from './pages/SecondChild' import Third from './pages/Third' const App = () => ( <BrowserRouter> <h1>react-routerに入門する。</h1> <nav> <ul> <li><Link to='/'>Index</Link></li> <li><Link to='/second'>Second</Link></li> <li><Link to='/second/neko'>Second-neko</Link></li> <li><Link to='/third'>Third</Link></li> </ul> </nav> <article> <Route exact path='/' component={Index} /> <Route path='/second' component={Second} /> <Route path='/second/:id' component={SecondChild} /> <Route path='/third' component={Third} /> </article> </BrowserRouter> ) export default Appあれっ、ふたつ出ちゃった。
SecondとSecondChildを逆に書くべきだった?と調べてみるもそういうことではなく。
単純にexactの記載が抜けていたのでした。<article> <Route exact path='/' component={Index} /> <Route exact path='/second' component={Second} /> <Route path='/second/:id' component={SecondChild} /> <Route path='/third' component={Third} /> </article>Routeは前方一致するものがあれば全てのコンポーネントが表示されるため、一致させたくないものにはexactが必要です。
これで完全一致の場合のみ表示されるようになります。余談
今回記事を書くにあたって、vue-routerで言うところの
:to={name: 'hoge'}
的な書き方をしたいと思ったのですが、どうにも書き方を見付けられませんでした。
単に見付けられていないのか、そもそもreactでは必要にならないのか……。
触っていくうちに分かると思うので、今後の課題とします。参考記事
react-router@v4を使ってみよう:シンプルなtutorial
https://qiita.com/muiscript/items/b4ca1773580317e7112eReact Roter v4 (RRv4) を使用した時の備忘録
https://blog.kazu69.net/2017/08/10/using-react-router-v4/
- 投稿日:2019-07-08T03:49:55+09:00
useEffectでcomponentDidMountを代用する
componentDidMountをやめる
「hooksで全部書いていきたい!」とはあまり思わないが、
1からFCでコンポーネントを書き始めると、
あとで「componentDidMountいるじゃん」となったときに面倒くさいことが多々あったので、
この際覚えちゃおうというと、いろいろ試してみる。最終完成品
https://codesandbox.io/embed/dank-shape-mb1mh軽く実装してみた(駄目な例)
codeSandBoxを利用したのをそのまま載せているので、細かいことは大きな心でスルーしてください。
import React, { useState, useEffect } from "react"; import ReactDOM from "react-dom"; const App = () => { return ( <div className="App"> <CountButtons initialCount={10} /> </div> ); }; const CountButtons = ({ initialCount }) => { const [count, setCount] = useState(initialCount); const countUp = () => setCount(count + 1); const countDown = () => setCount(count - 1); useEffect(() => { console.log("useEffect"); }); return ( <> <p>{count}</p> <button onClick={countUp}>↑↑increment↑↑</button> <button onClick={countDown}>↓↓decrement↓↓</button> </> ); }; const rootElement = document.getElementById("root"); ReactDOM.render(<App />, rootElement);useEffectはこんな感じで書くと、renderするたびに実行されていくようだ。
ボタンをクリックした後の再レンダリングでも発火してしまっているのがコンソールを見るとわかる。
なので、この書き方ではcomponentDidMountの動きは再現できない。修正後
では、componentDidMountみたいにするにはどうしたらいいか。
初回レンダリングのときのみ発火させたい。その時は第2引数に発火させる条件の変数を配列で入れてあげればいいようだ。
import React, { useState, useEffect } from "react"; import ReactDOM from "react-dom"; const App = () => { return ( <div className="App"> <CountButtons initialCount={10} /> </div> ); }; const CountButtons = ({ initialCount }) => { const [count, setCount] = useState(initialCount); const countUp = () => setCount(count + 1); const countDown = () => setCount(count - 1); useEffect(() => { console.log("useEffect"); }, [initialCount]); // ここにinitialCountを入れる return ( <> <p>{count}</p> <button onClick={countUp}>↑↑increment↑↑</button> <button onClick={countDown}>↓↓decrement↓↓</button> </> ); }; const rootElement = document.getElementById("root"); ReactDOM.render(<App />, rootElement);こうすると何が起きるのかというと、
初期レンダリング時にpropsで渡されるinitialCountが来て、
その値を見て、useEffectが発火する。なので2回目以降はinitialCountの値は変わらないので、
ボタンをクリックしてもuseEffectは発火しない
→componentDidMountの出来上がり。更新ボタンを押したときのみuseEffectがコンソールログに出るので、
ちゃんと初期レンダリングのみ発火するようになっている。propsがないとき
propsがあるからcomponentDidMountのように振る舞えているようにも見えるので、
propsがないときのパターンを考えてみる。useEffectを発火させるのは、初期レンダリングにのみ定義されているものを第2引数に入れればいいので、
setCountをいれて試してみる。import React, { useState, useEffect } from "react"; import ReactDOM from "react-dom"; const App = () => { return ( <div className="App"> <CountButtons /> </div> ); }; const CountButtons = () => { // propsを消す const [count, setCount] = useState(10); const countUp = () => setCount(count + 1); const countDown = () => setCount(count - 1); useEffect(() => { console.log("useEffect"); }, [setCount]); // useStateで定義した関数を入れてみる return ( <> <p>{count}</p> <button onClick={countUp}>↑↑increment↑↑</button> <button onClick={countDown}>↓↓decrement↓↓</button> </> ); }; const rootElement = document.getElementById("root"); ReactDOM.render(<App />, rootElement);こんな感じにしておけばいいのではと思い実行。
できた。
なるほどね。注意点
いろいろなサイトでこのuseEffectについて調べていたが、
第2引数に空配列[]
を入れても動くみたいだけど、アンチパターンらしい。
よくわからないが、人的ミスを起こしやすくなるとか。componentDidMountでよくね?
useEffectでcomponentDidMountの振る舞いをできるように実装してみたが、
useEffect自体がたくさんの処理を行えるので、
どんな処理がなされているのかを細かく見ないと、修正するのが大変になりそう。それこそバグの原因にないかねない気がする。
実際につかっていって、これは使わないほうがいいわってなったときは
また記事にでもしましょうか。。。
- 投稿日:2019-07-08T01:22:30+09:00
RailsアプリにWebpacker(React + TypeScript)をセットアップする
はじめに
作成中のRailsアプリのフロントエンドにReactを使いたかった。
Railsアプリ上でReactを利用する方法は複数あるらしい。
RailsでReact.jsを使ういくつかの方法
2016年時点で、RailsでReact.jsを使う方法はいくつかあって、どれを採用するかで悩みました。
- vendor/assets/javascripts にreact.jsを置いて利用する
- react-rails gem を利用する
- browserify-rails で npm管理して利用する
- railsプロジェクト内に、JavaScript開発用のディレクトリを用意して webpack + babel-loader で利用する
調査したところ、だいたいこんなパターンがあると思っていて、下に行くほどRailsよりもJavaScript開発の知識が必要になってくるイメージでした。
webpackを使った Rails上でのReact開発 - クックパッド開発者ブログ より
できるだけモダンな方法を採用したかったが、
- webpackをいきなり採用する自信がなかった
- 仕事先でWebpackerを使っているプロジェクトがあった
という理由で、Railsのgemとしてwebpackを扱えるWebpackerを採用することに。
せっかくなので個人的に勉強していたTypeScriptも合わせて導入してみる。
方法
READMEをちゃんと読んで進める。
rails/webpacker/README.md - Github
1.Webpackerのインストール
Gemfile.gem 'webpacker'$bundle install $bundle exec rails webpacker:install自分がこれから設定していくWebpack環境のビルドは以下のように行う。
$bin/webpack-dev-serverwebpackのビルド
$bin/webpack2.Reactを使えるようにする
$bundle exec rails webpacker:install:react3.TypeScriptを使えるようにする
$bundle exec rails webpacker:install:typescript $yarn add @types/react @types/react-dom4.jsxファイルをtsxに変更
$mv hello_react.jsx hello_react.tsx5.tsxファイルの中身を編集
app/javascript/packs/hello_react.tsximport React from "react"; import ReactDOM from "react-dom"; interface HelloProps { name: string; } const Hello: React.SFC<HelloProps> = props => ( <div>Hello {props.name}!</div> ) Hello.defaultProps = { name: "David", } document.addEventListener("DOMContentLoaded", () => { ReactDOM.render( <Hello name="React" />, document.body.appendChild(document.createElement("div")), ) })Webpacker で React + TypeScript - Qiita より
6.ビルドが成功したらhello_react.tsxファイルを挿入したい任意のRailsのviewsファイルに
<%= javascript_pack_tag 'hello_react' %>
という形で挿入。app/views/static_pages/index.html.erb... <section> <%= javascript_pack_tag 'hello_react' %> </section> ...7.1~5で作成されたor編集したファイルなど
package.json{ "name": "MyRailsApp", "private": true, "dependencies": { "@babel/preset-react": "^7.0.0", "@rails/webpacker": "^4.0.6", "@types/react": "^16.8.23", "@types/react-dom": "^16.8.4", "babel-plugin-transform-react-remove-prop-types": "^0.4.24", "prop-types": "^15.7.2", "react": "^16.8.6", "react-dom": "^16.8.6", "ts-loader": "^6.0.4", "tslint": "^5.18.0", "tslint-config-airbnb": "^5.11.1", "tslint-loader": "^3.5.4", "typescript": "^3.5.2", "webpack-dev-server": "^3.5.1" } }tsconfig.json{ "compilerOptions": { "declaration": false, "emitDecoratorMetadata": true, "experimentalDecorators": true, "lib": ["es6", "dom"], "module": "es6", "moduleResolution": "node", "baseUrl": ".", "paths": { "*": ["node_modules/*", "app/javascript/*"] }, "sourceMap": true, "target": "es5", "allowSyntheticDefaultImports": true, // 追加 "jsx": "react" // 追加 }, "exclude": [ "**/*.spec.ts", "node_modules", "vendor", "public" ], "compileOnSave": false }tslint.json// 追加↓ { "extends": ["tslint-config-airbnb", "tslint-react", "tslint-config-prettier"], "rules": { "variable-name": [true, "ban-keywords", "check-format", "allow-pascal-case"] } }webpacker.yml... extensions: - .jsx // 追加 - .tsx ...config/webpack/*.jsは特に修正しなかった気がする。
loaderの変更もややこそうだったのでなし。config/webpack/environment.jsconst { environment } = require('@rails/webpacker') const typescript = require('./loaders/typescript') environment.loaders.prepend('typescript', typescript) module.exports = environmentconfig/webpack/loaders/typescript.jsconst PnpWebpackPlugin = require('pnp-webpack-plugin') module.exports = { test: /\.(ts|tsx)?(\.erb)?$/, use: [ { loader: 'ts-loader', options: PnpWebpackPlugin.tsLoaderOptions() } ] }感想
いろんなファイルが生成されたのでどこをいじればいいかわからず大変だった。
Linterのエラーが出まくったりビルドが通らなくていろいろ修正したりして沼になったりしたが、READMEとエラー文に忠実に進めていくのが大事。
- 投稿日:2019-07-08T00:51:33+09:00
【2019年7月版】TypeScript はじめの一歩
TypeScript を使用したプロジェクトの始め方
TypeScript での開発の始め方がフレームワークやそのバージョンによって色々ありますので現時点での設定手順を棚卸いたしました。
バージョンについて
執筆において使用した各種コマンド・モジュールのバージョンを列挙しておきます。
- node: 10.15.3
- npm: 6.9.0
- yarn: 1.16.0
- typescript: 3.5.2
- nuxt: 2.8.1
- react: 16.8.6
- react-scripts: 3.0.1
- angular: 7.2.0
- angular-cli: 7.3.8
- deno: 0.10.0
1. npm
以下は npm を使用してシンプルに Typescript を開始する手順です。
1-1. プロジェクト作成
npm init
コマンドで適当なプロジェクトを作成いたします。$ mkdir npm_typescript_sample $ cd npm_typescript_sample $ npm init This utility will walk you through creating a package.json file. It only covers the most common items, and tries to guess sensible defaults. See `npm help json` for definitive documentation on these fields ...npm の質問には適宜、回答しておきます。
1-2. TypeScriptをプロジェクトに追加
$ npm i -D typescript npm notice created a lockfile as package-lock.json. You should commit this file. npm WARN typescript_install@1.0.0 No description npm WARN typescript_install@1.0.0 No repository field. + typescript@3.5.2 added 1 package from 1 contributor and audited 1 package in 981.308s found 0 vulnerabilities1-3. TypeScript 初期設定
tsc --init
コマンドでtsconfig.json
を生成します。$ npx tsc --init message TS6071: Successfully created a tsconfig.json file.tsconfigはとりあえず初期設定のままで動作確認をいたします。
1-4. 起動スクリプトを追記
package.json に以下のように起動スクリプトを追記しておきます。
package.json{ ... "scripts": { "start": "tsc -p . && node .", "test": "echo \"Error: no test specified\" && exit 1" }, ... }1-5. 起動
適当に以下のような 'index.ts' ファイルを作成いたします。
$ touch index.tsindex.tsconsole.log("hello world.");もう、全然 TypeScriptじゃなくてすいません・・・
以下のコマンドで起動できます。$ npm start ... hello world.TypeScript、起動できました!
1-6. js 生成先の変更
デフォルトでは index.ts と同じディレクトリにindex.jsが生成されます。
捨てスクリプトを書く分には問題ありませんがちょっと規模の大きいプロジェクトになると気になってくると思います。
その場合は tsから生成されるjsの出力先をtsconfig.json
にて変更できます。tsconfig.json{ "compilerOptions": { ... "outDir": "./dist", ... }}起動スクリプトも以下のように
dist
以下を参照するように修正しておきます。package.json... "start": "tsc -p . && node dist/.", ...2. yarn
以下は yarn を使用してシンプルに TypeScript を開始する手順です。
基本的な手順は npm と一緒です。2-1. プロジェクト作成
$ mkdir yarn_typescript_sample $ cd yran_typescript_sample $ yarn init yarn init v1.16.0 question name (yarn_typescript_sample): question version (1.0.0): question description: question entry point (index.js): question repository url: question author: question license (MIT): question private: success Saved package.json ✨ Done in 8.95s.2-2. TypeScriptをプロジェクトに追加
$ yarn add -D typescript yarn add v1.16.0 info No lockfile found. [1/4] ? Resolving packages... [2/4] ? Fetching packages... [3/4] ? Linking dependencies... [4/4] ? Building fresh packages... success Saved lockfile. success Saved 1 new dependency. info Direct dependencies └─ typescript@3.5.2 info All dependencies └─ typescript@3.5.2 ✨ Done in 5.67s.2-3. TypeScript 初期設定
tsc --init
コマンドでtsconfig.json
を生成します。$ yarn run tsc --init ... message TS6071: Successfully created a tsconfig.json file. ✨ Done in 1.02s.先ほどと同様にtsconfigはとりあえず初期設定のままで動作確認をいたします。
2-4. 起動スクリプトを追記
package.json に以下のように起動スクリプトを追記しておきます。
package.json{ ... "version": "1.0.0", "scripts": { "start": "tsc -p . && node ." }, "main": "index.js", ... }2-5. 起動
適当に以下のような 'index.ts' ファイルを作成いたします。
$ touch index.tsindex.tsconsole.log("hello world.");以下のコマンドで起動できます。
$ yarn start yarn run v1.16.0 $ tsc -p . && node . hello world. ✨ Done in 6.16s.TypeScript、起動できました!
3. Nuxt.js
3-1. スターターキットを使用してプロジェクトを作成
以下は Nuxt.js のスターターキット
create-nuxt-app
を使用する手順です。$ yarn create nuxt-app nuxt_typescript_app yarn create v1.16.0 [1/4] ? Resolving packages... [2/4] ? Fetching packages... [3/4] ? Linking dependencies... [4/4] ? Building fresh packages... success Installed "create-nuxt-app@2.8.0" with binaries: - create-nuxt-app create-nuxt-app v2.8.0 ✨ Generating Nuxt.js project in /Users/xxx/nuxt_typescript_app ? Project name nuxt_typescript_app ? Project description My superior Nuxt.js project ? Author name Yoshinori Koide ? Choose the package manager Yarn ? Choose UI framework Bootstrap Vue ... ✨ Done in 13.89s. ? Successfully created project nuxt_typescript_app To get started: cd nuxt_typescript_app yarn dev To build & start for production: cd nuxt_typescript_app yarn build yarn start To test: cd nuxt_typescript_app yarn test ✨ Done in 354.85s. $ yarn dev yarn run v1.16.0 $ cross-env NODE_ENV=development nodemon server/index.js --watch server [nodemon] 1.19.1 ...上記で http://localhost:3000 に開発サイトが立ち上がります。
ここから先の手順はちょと長いので以下のサイトをご覧ください。すいません。。。
3-2. スクラッチで構築
スターターキットを使用せずに、まっさらな Next.js プロジェクトに TypeScript を追加する手順です。
3-2-1. プロジェクトの作成
まずは新規プロジェクト作成してnuxt.jsを追加します。
ここでは yarn を使用しますが npm でも同様です。$ mkdir nuxt_typescript_manual_sample $ cd nuxt_typescript_manual_sample $ yarn init yarn init v1.16.0 question name (nuxt_typescript_manual_sample): question version (1.0.0): question description: question entry point (index.js): question repository url: question author: question license (MIT): question private: success Saved package.json ✨ Done in 5.43s. $ yarn add nuxt yarn add v1.16.0 info No lockfile found. [1/4] ? Resolving packages... warning nuxt > @nuxt/webpack > postcss-preset-env > postcss-color-functional-notation > postcss-values-parser > flatten@1.0.2: I wrote this module a very long time ago; you should use something else. [2/4] ? Fetching packages... [3/4] ? Linking dependencies... [4/4] ? Building fresh packages... ... ├─ yallist@3.0.3 └─ yargs@3.32.0 ✨ Done in 91.48s.3-2-2. TypeScript 追加
続いて TypeScript サポートを追加します。
$ yarn add -D @nuxt/typescript yarn add v1.16.0 [1/4] ? Resolving packages... warning @nuxt/typescript > @types/chokidar@2.1.3: This is a stub types definition. chokidar provides its own type definitions, so you do not need this installed. [2/4] ? Fetching packages... [3/4] ? Linking dependencies... [4/4] ? Building fresh packages... ... ├─ typescript@3.5.2 └─ worker-rpc@0.1.1 ✨ Done in 32.68s. $ yarn add ts-node yarn add v1.16.0 [1/4] ? Resolving packages... [2/4] ? Fetching packages... [3/4] ? Linking dependencies... warning " > ts-node@8.3.0" has unmet peer dependency "typescript@>=2.0". [4/4] ? Building fresh packages... success Saved lockfile. success Saved 4 new dependencies. info Direct dependencies └─ ts-node@8.3.0 info All dependencies ├─ arg@4.1.0 ├─ make-error@1.3.5 ├─ ts-node@8.3.0 └─ yn@3.1.0 ✨ Done in 22.41s. $ touch tsconfig.json $ touch nuxt.config.ts
tscongig.json
は nuxt 初回起動時に宜しくやってくれますので空白のままでOKです。
nuxt.config.ts
は以下の内容で保存しておきます。nuxt.config.tsimport NuxtConfiguration from '@nuxt/config' const config: NuxtConfiguration = { // タイプするか `Ctrl + Space` を押すとオートコンプリートできます } export default config3-2-3. 起動スクリプトの追加
nuxt
コマンドを叩くだけのdev
スクリプトを追加します。package.json... "version": "1.0.0", "scripts": { "dev": "nuxt" }, "main": "index.js", ...3-2-4. 初期ページの作成
index ページを作成します。
$ mkdir pages $ touch pages/index.vue内容は以下のようにしておきます。
index.vue<template> <h1>Hello world!</h1> </template>3-2-5. 起動
あとは
dev
スクリプトを呼び出すだけです。$ yarn dev yarn run v1.16.0 $ nuxt ℹ Generating /tsconfig.json 22:16:41 ╭─────────────────────────────────────────────╮ │ │ │ Nuxt.js v2.8.1 │ │ Running in development mode (universal) │ │ TypeScript support is enabled │ │ │ │ Listening on: http://localhost:3000/ │ │ │ ╰─────────────────────────────────────────────╯ ...http://localhost:3000 にて
hello world
が表示されます。
上記では yarn を使用しておりますが、npm run dev
でも同じです。4. React
React にて TypeScript を有効にする手順です。
すっぴんのReactにTypeScriptを組み込んでいくのは非常に手間なので最初からスターターキットを使用します。4-1. npm(npx) を使用してプロジェクト作成
npm を使用する場合、以下の手順です。
$ npx create-react-app react-typescript-npm-app --typescript npx: 91個のパッケージを19.153秒でインストールしました。 ... Success! Created react-typescript-npm-app at /Users/xxx/react-typescript-npm-app Inside that directory, you can run several commands: yarn start Starts the development server. yarn build Bundles the app into static files for production. yarn test Starts the test runner. yarn eject Removes this tool and copies build dependencies, configuration files and scripts into the app directory. If you do this, you can’t go back! We suggest that you begin by typing: cd react-typescript-npm-app yarn start Happy hacking! $ cd react-typescript-npm-app $ npm start ... Starting the development server... ...で、http://lcoalhost:3000 にて開発サイトが立ち上がります。便利。
(なんかyarnがインストールされているせいか?yarnでのコマンドが表示されておりますが・・・)4-2. yarn を使用してプロジェクト作成
yarn を使用する場合、以下の手順です。
$ yarn create react-app react-typescript-yarn-app --typescript ... $ cd react-typescript-yarn-app $ yarn start ... Starting the development server... ...で、http://lcoalhost:3000 にて開発サイトが立ち上がります。楽チン。
5. Angular でプロジェクト作成
Angular はそもそも TypeScript を使用しますので、普通にプロジェクトを作成すればOKです。
$ ng n ang-sample-app ... $ cd ang-sample-app $ ng serve上記のコマンドで http://localhost:4200 にて開発サイトが立ち上がります。
番外編:deno
TypeScript を
そのまま
動かす(というかjsの変換を宜しくやってくれる)エンジンとしてdeno
があります。
既存のjsライブラリは一切使えませんが、ネイティヴTypeScriptのビッグウェイヴにライドオンしたいという方はdeno
もおすすめ(?)です。最新版をインストールしてサンプルを動かしてみる手順は以下です。
$ curl -fsSL https://deno.land/x/install/install.sh | sh ... $ deno version deno: 0.10.0 v8: 7.7.37 typescript: 3.5.1 $ deno https://deno.land/welcome.ts Download https://deno.land/welcome.ts Compile https://deno.land/welcome.ts Welcome to Deno ?デノザウラー?が表示されましたね。・・・はい。
(個人的には deno 推しです。)さいごに
npm i -g typescript
はやめよう!参考サイト
- 投稿日:2019-07-08T00:07:22+09:00
React × WebAssembly の動作サンプルをAssemblyScriptで簡単に作成してみる
こちらのReactとAssemblyScriptの環境作成が、簡単にできて素晴らしかったので、自分でも試して投稿させていただきました。m(_ _)m
AssemblyScriptについてはこちら
自分で試してみたコードはこちらです
create-react-app
でプロジェクト作成# reactのプロジェクト作成 yarn create react-app webassembly-in-react cd webassembly-in-react/ # VSCodeを使っている場合はこれでVSCodeを開き直せる # code -r webassembly-in-react/ # AssemblyScriptを追加する yarn add -D AssemblyScript/assemblyscript # AssemblyScriptの例となるtsファイルの追加、package.jsonにscriptの追加 を自動でやってくれる yarn asinit .
package.json
package.json
のscriptを書き換えて、AssemblyScriptのビルドと、reactのビルドを行うように変更します。package.json"scripts": { "jsstart": "react-scripts start", "jsbuild": "react-scripts build", "asbuild": "asc assembly/index.ts -b public/as-api.wasm", "start": "npm run asbuild && npm run jsstart", "build": "npm run asbuild && npm run jsbuild" },
package.json
全体package.json{ "name": "webassembly-in-react", "version": "0.1.0", "private": true, "dependencies": { "react": "^16.8.6", "react-dom": "^16.8.6", "react-scripts": "3.0.1" }, "scripts": { "jsstart": "react-scripts start", "jsbuild": "react-scripts build", "asbuild": "asc assembly/index.ts -b public/as-api.wasm", "start": "npm run asbuild && npm run jsstart", "build": "npm run asbuild && npm run jsbuild" }, "eslintConfig": { "extends": "react-app" }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] }, "devDependencies": { "assemblyscript": "AssemblyScript/assemblyscript" } }
assembly/index.ts
yarn asinit .
で自動生成された、assembly/index.ts
にscriptを追加します。※TypeScriptではなく、AssemblyScriptで書かれています
assembly/index.tsexport function factorial(value: f64): f64 { if (value == 0 || value == 1) return 1; return value * factorial(value - 1); }
src/wa-api.js
↑のAssemblyScriptを読み込むためのローダーを作成
src/wa-api.jsimport {instantiateStreaming} from "assemblyscript/lib/loader"; export default instantiateStreaming( fetch('./as-api.wasm') );
src/App.js
ReactからAssemblyScriptを実行するように変更
src/App.jsimport React, { useState } from 'react'; import waApi from './wa-api'; function App() { const [value, setValue] = useState(5); const [result, setResult] = useState(); return ( <div className="App"> <p> The factorial of <input value={value} onChange={evt => setValue(evt.target.value)} /> is {result} </p> <button onClick={async () => setResult((await waApi).factorial(value))}> Calculate </button> </div> ); } export default App;この状態でビルドします
yarn start
ReactからAssemblyScriptを実行できました、素晴らしいチュートリアルでした。
読んでいただいてありがとうございました。m(_ _)m
- 投稿日:2019-07-08T00:07:22+09:00
ReactにWebAssemblyを追加した動作サンプルをAssemblyScriptで簡単に作成してみる
こちらのReactとAssemblyScriptの環境作成が、簡単にできて素晴らしかったので、自分でも試して投稿させていただきました。m(_ _)m
AssemblyScriptについてはこちら
自分で試してみたコードはこちらです
create-react-app
でプロジェクト作成# reactのプロジェクト作成 yarn create react-app webassembly-in-react cd webassembly-in-react/ # VSCodeを使っている場合はこれでVSCodeを開き直せる # code -r webassembly-in-react/ # AssemblyScriptを追加する yarn add -D AssemblyScript/assemblyscript # AssemblyScriptの例となるtsファイルの追加、package.jsonにscriptの追加 を自動でやってくれる yarn asinit .
package.json
package.json
のscriptを書き換えて、AssemblyScriptのビルドと、reactのビルドを行うように変更します。package.json"scripts": { "jsstart": "react-scripts start", "jsbuild": "react-scripts build", "asbuild": "asc assembly/index.ts -b public/as-api.wasm", "start": "npm run asbuild && npm run jsstart", "build": "npm run asbuild && npm run jsbuild" },
package.json
全体package.json{ "name": "webassembly-in-react", "version": "0.1.0", "private": true, "dependencies": { "react": "^16.8.6", "react-dom": "^16.8.6", "react-scripts": "3.0.1" }, "scripts": { "jsstart": "react-scripts start", "jsbuild": "react-scripts build", "asbuild": "asc assembly/index.ts -b public/as-api.wasm", "start": "npm run asbuild && npm run jsstart", "build": "npm run asbuild && npm run jsbuild" }, "eslintConfig": { "extends": "react-app" }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] }, "devDependencies": { "assemblyscript": "AssemblyScript/assemblyscript" } }
assembly/index.ts
yarn asinit .
で自動生成された、assembly/index.ts
にscriptを追加します。※TypeScriptではなく、AssemblyScriptで書かれています
assembly/index.tsexport function factorial(value: f64): f64 { if (value == 0 || value == 1) return 1; return value * factorial(value - 1); }
src/wa-api.js
↑のAssemblyScriptを読み込むためのローダーを作成
src/wa-api.jsimport {instantiateStreaming} from "assemblyscript/lib/loader"; export default instantiateStreaming( fetch('./as-api.wasm') );
src/App.js
ReactからAssemblyScriptを実行するように変更
src/App.jsimport React, { useState } from 'react'; import waApi from './wa-api'; function App() { const [value, setValue] = useState(5); const [result, setResult] = useState(); return ( <div className="App"> <p> The factorial of <input value={value} onChange={evt => setValue(evt.target.value)} /> is {result} </p> <button onClick={async () => setResult((await waApi).factorial(value))}> Calculate </button> </div> ); } export default App;この状態でビルドします
yarn start
ReactからAssemblyScriptを実行できました、素晴らしいチュートリアルでした。
読んでいただいてありがとうございました。m(_ _)m