2019年05月14日

ReactでpropsとRecomposeとReduxでpropsを引き渡すサンプル

Reactでpropsとして受け取る値には親要素から受け取ったprops以外に、RecomposeでEnhanceされたporpsやstate、Reduxでconnectされたstoreの値などがあるので出し分けのサンプル

import React, { useState } from "react";
import ReactDOM from "react-dom";
import { compose, withStateHandlers } from "recompose";
import { createStore } from "redux";
import { Provider, connect } from "react-redux";

const Foo = ({ no, changeNo, no2, changeNo2, no3, changeNo3 }) => {
const handleClick = () => {
changeNo(no + 1);
};
const handleClick2 = () => {
changeNo2(no2 + 1);
};
const handleClick3 = () => {
changeNo3(no3 + 1);
};
return (
<div>
<p>props:{no}</p>
<input value="+" type="button" onClick={handleClick} />
<p>recomoseState:{no2}</p>
<input value="+" type="button" onClick={handleClick2} />
<p>connectedState:{no3}</p>
<input value="+" type="button" onClick={handleClick3} />
</div>
);
};

const ConnectedFoo = connect(
state => ({
no3: state.no3
}),
dispatch => ({
changeNo3: no => {
dispatch(changeNo3(no));
}
})
)(Foo);

const EnhancedFoo = compose(
withStateHandlers(
() => ({
no2: 0
}),
{
changeNo2: props => () => ({
no2: props.no2 + 1
})
}
)
)(ConnectedFoo);

const App = () => {
const [no, changeNo] = useState(0);
return (
<div>
<EnhancedFoo no={no} changeNo={changeNo} />
</div>
);
};

function changeNo3(no3) {
return {
type: "CHANGE_NO3",
no3
};
}

const initialState = {
no3: 0
};

const store = createStore((state = initialState, action) => {
switch (action.type) {
case "CHANGE_NO3":
return {
no3: action.no3
};
default:
return state;
}
});

const rootElement = document.getElementById("root");
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
rootElement
);




posted by ねこまんま at 03:51 | React | 更新情報をチェックする

2019年04月01日

ReactをGAE(Google App Engine)上にCloud Buildを使ってデプロイ

前回(ReactをGAE(Google App Engine)上でSSR)でGAE(Google App Engine)上にデプロイはできたのですがこのままだとGAEの権限があるアカウントしかリリース作業ができないためGitHubのmasterにプッシュされたら自動でGAEにリリースされるようにしていきます。

Cloud Source Repositoryを開き対処したいリポジトリを読み込みます。
Cloud Build からトリガーを作成

トリガーのタイプ:ブランチ
ブランチ:master
Cloud Build 構成ファイル: チェック
Cloud Build 構成ファイルの場所: cloudbuild.yaml
変数
_ENVIRONMENT: production
としてます

cloudbuild.yamlを作成して以下のような内容にして

steps:
- name: 'alpine'
args: ['echo', '${_ENVIRONMENT}']
- name: 'gcr.io/cloud-builders/npm'
args: ['install']
- name: 'gcr.io/cloud-builders/npm'
args: ['run', 'release']
- name: 'gcr.io/cloud-builders/gcloud'
args: ['app', 'deploy', '--version', '1', 'app.yaml']


masterにコミットすればデプロイがされるはず、以下のようなビルドエラーが出る場合は指定されるURLにアクセスしてAPIに認証情報与えてあげる必要があります。

Step #2: ERROR: (gcloud.app.deploy) User [xxx@cloudbuild.gserviceaccount.com] does not have permission to access app [xxx] (or it may not exist): App Engine Admin API has not been used in project xxx before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/appengine.googleapis.com/overview?project=xxx then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.


参考:GCPのCloud Buildを試してみた - Qiita
posted by ねこまんま at 16:24 | React | 更新情報をチェックする

2019年03月29日

ReactをGAE(Google App Engine)上でSSR

SSRシリーズ(1,2,3)、最後はGAE(Google App Engine)上でReactをSSRしていきます。

まずはGoogle Cloud Platform 上でプロジェクトを作成、次にプロジェクトのApp Engineを作成、node.jsのスタンダード環境でよい

参考:GCP プロジェクトの作成

package.jsonはstartがGAEの起動オプションになるのでそれ以外に割り当てるように修正、clientとserverで処理を整理


"scripts": {
"start": "node server.dist.js",
"dev": "npm run start:client & npm run start:server",
"release": "npm run release:client & npm run release:server",
"start:client": "webpack --mode development -w",
"release:client": "webpack --mode production",
"start:server": "npm run release:server && node ./server.dist.js",
"release:server": "webpack --config webpack.config.server.js"
},


app.yamlを作成


runtime: nodejs8


参考:Node.js によるウェブサービスの作成


次にCloud SDK をインストール

以下のコマンドでGAE環境にデプロイできます。


gcloud app deploy


ブラウザで確認したい場合は以下のコマンドで確認できます。


gcloud app browse
posted by ねこまんま at 16:05 | React | 更新情報をチェックする

2019年03月28日

ReactでSSR(タイトル、メタ、OGP)

SSRSSR(ルーティング)と対応してきたのでSSR(タイトル、メタ、OGP)に対応します。

SSRを行う際にタイトル、メタ、OGPなどを変更したいという要望は大きいと思います。

これはreact-helmetというライブラリを利用することで簡単に対応が可能です。

以下のように読み込むことでブラウザレンダリング上は簡単にタイトル、メタ、OGPを変更できます。


import React from 'react';
import {Helmet} from "react-helmet";

export const Home = () => (<>
<Helmet>
<title>Home</title>
<meta property="og:description" content="Home" />
</Helmet>
<h1>React Home</h1>
</>)


サーバーサイドレンダリング上では以下のように利用します。


import express from 'express'
import React from 'react'
import ReactDOMServer from 'react-dom/server';
import { StaticRouter } from 'react-router-dom';
import {Helmet} from "react-helmet";

import { App } from './src/App.js'

const app = express()

app.use(express.static('./dist'));

app.get('/*', (req, res) => {
const context = {};
const app = ReactDOMServer.renderToString(
<StaticRouter location={req.url} context={context}>
<App />
</StaticRouter>
);
const helmet = Helmet.renderStatic();

const html = `
<!doctype html>
<html ${helmet.htmlAttributes.toString()}>
<head>
${helmet.title.toString()}
${helmet.meta.toString()}
${helmet.link.toString()}
</head>
<body ${helmet.bodyAttributes.toString()}>
<div id="app">
${app}
</div>
<script src="/script.js"></script>
</body>
</html>
`;

return res.send(html)
})

app.listen(3000)
posted by ねこまんま at 18:14 | React | 更新情報をチェックする

2019年03月18日

ReactでSSR(ルーティング)

前回(ReactでSSR)は単純なSSRをやったので今回はルーティングを含めた対応をやっていきます。

まずはreact-router-domのインストールを行います。

npm install react-router-dom


まずはReactのみでルーティング



react-router-domのBrowserRouterを読み込みAppコンポーネントを包みます。ちなみにサーバーサイドではBrowserRouterではなくStaticRouterという機能を利用するのでサーバーサイドに影響を受けないレイヤーで記述しておく必要があります。
また、ReactDOM.renderではなくReactDOM.hydrateを利用しています。ReactDOM.hydrateを利用することでSSRされたDOMをベースにReactがアプリケーションを構築してくれるようになります。

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from "react-router-dom";
import { App } from './App';

ReactDOM.hydrate(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('app')
);


App.jsではHomeコンポーネントとAboutコンポーネントを読み込みルーティングに準じて表示を切り替えています。

import React from 'react';
import { Home } from './Home';
import { About } from './About';
import { Route, Link } from "react-router-dom";

export const App = () => (<div>
<Link to="/">Home</Link>
<Link to="/about/">About</Link>
<Route exact path="/" component={Home} />
<Route path="/about/" component={About} />
</div>)


Home.jsとAbout.jsでは適当なコンポーネントを定義しています。

import React from 'react';
export const Home = () => <h1>React Home</h1>


import React from 'react';
export const About = () => <h1>React About</h1>



クライントサイドはこれでちゃんと動作しますが、http://localhost:3000/aboutでリロードをするとファイルがないと怒られてしまいます。

server.jsは次のように変更します。StaticRouterにlocationを与えてReactDOMServer.renderToString()を行うことでそのURLで描画されるべきHTMLが表示されるのでそれをHTMLに挿入しておきます。

import express from 'express'
import React from 'react'
import ReactDOMServer from 'react-dom/server';
import { StaticRouter } from 'react-router-dom';
import fs from 'fs'
import path from 'path'
import { App } from './src/App.js'

const app = express()

app.use(express.static('./dist'));

app.get('/*', (req, res) => {
const context = {};
const app = ReactDOMServer.renderToString(
<StaticRouter location={req.url} context={context}>
<App />
</StaticRouter>
);

fs.readFile(path.resolve('./dist/index.html'), 'utf8', (err, data) => {
return res.send(
data.replace(
'<div id="app"></div>',
`<div id="app">${app}</div>`
)
)
})
})

app.listen(3000)


これで変更は終了です。次はReact Helmetとの連携です。

参考:Using React Router 4 with Server-Side Rendering ← Alligator.io
posted by ねこまんま at 15:28 | React | 更新情報をチェックする

2019年03月16日

ReactでSSR

実験的にReactでSSRを行っていく。まずはローカルでExpressサーバーを立ててSSRを行う。

まずは普通にReactでページを表示



まずはクライアントのJS用に以下のコマンドで各種ツールをインストール

npm init -y
npm install --save-dev webpack
npm install --save-dev babel-loader @babel/core @babel/preset-env @babel/preset-react
npm install react react-dom


package.jsonのscriptsにはビルド用のコマンドを設定、babelの設定も追加しておく

  "scripts": {
"build": "webpack --mode development",
"start": "webpack --mode development -w",
"release": "webpack --mode production"
},
"babel": {
"presets": [
"@babel/preset-env",
"@babel/preset-react"
]
},



webpack.config.jsを作成

const path = require('path');

module.exports = {
entry: "./src/script.js",
output: {
path:path.resolve(__dirname, "dist"),
filename: "script.js"
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader"
}
]
}
};


src/App.jsにAppコンポーネントを定義して

import React from 'react';

export const App = () => <h1>Hello React</h1>


src/script.jsにAppコンポーネントを出力するReactを書いて

import React from 'react';
import ReactDOM from 'react-dom';
import { App } from 'App';

ReactDOM.render(
<App />,
document.getElementById('app')
);




dist/index.htmlを設定

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="app"></div>
<script src="./script.js"></script>
</body>
</html>


これでnpm run buildしてdist/index.htmlを表示するとhello worldが書き出されています。

サーバーの準備



次にサーバーの準備をしていきましょう。今回は後でSSRするためにnode.jsのサーバーExpressを用意します。

まずはExpressのインストール

npm install express


サーバー用の設定ファイルserver.jsを作成します。

'use strict'

const express = require('express')
const app = express()

app.use(express.static('dist'));

app.listen(3000)


dist/index.htmlがルートディレクトリになるように設定します。

ターミナルから以下のコマンドを打つと

node ./server.js


localhost:3000でHello React!が表示されます。

サーバーサイドでSSR



ここからが本題、サーバーサイドでSSRを行っていきます。

まずはJSXやES2015が解釈できるようにserver.jsをWebpackでコンパイルするようにします。

Webpackでnode.jsが扱えるようにwebpack-node-externalsをインストールして

npm install --save-dev webpack-node-externals


サーバー用の設定ファイルを以下のように定義します。

const path = require('path');
const nodeExternals = require('webpack-node-externals');

module.exports = {
mode: 'production',
entry: "./server.js",
target: 'node',
output: {
path:path.resolve(__dirname, ""),
filename: "./server.dist.js"
},
externals: [nodeExternals()],
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader"
}
]
}
};


これで./server.jsの内容をコンパイルしてserver.dist.jsに出力できるようになります。

package.jsonのscriptsに以下のコマンドを追加しておくと

  "scripts": {
・・・
"server": "npm run build:server && node ./server.dist.js",
"build:server": "webpack --config webpack.config.server.js"
},


npm run serverのコマンドでスクリプトのビルドとサーバーの起動をやってくれます。

server.jsは次のように変更します。

import  express from 'express'
import React from 'react'
import ReactDOMServer from 'react-dom/server'
import fs from 'fs'
import path from 'path'

import { App } from './src/App.js'

const app = express()

app.use(express.static('./dist'));

app.get('/', (req, res) => {
fs.readFile(path.resolve('./dist/index.html'), 'utf8', (err, data) => {
return res.send(
data.replace(
'<div id="app"></div>',
`<div id="app">${ReactDOMServer.renderToString(<App />)}</div>`
)
)
})
})

app.listen(3000)


ReactDOMServer.renderToString()でAppコンポーネントの内容がHTMLに変換されて<div id="app"></div>内に挿入されます。

書き出されるHTMLはこんな感じに。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="app"><h1 data-reactroot="">Hello React</h1></div>
<script src="./script.js"></script>
</body>
</html>


ひとまず今回はここまで。次回はルーティング周りの対応を入れていきます。
posted by ねこまんま at 11:48 | React | 更新情報をチェックする

2019年01月14日

FirebaseHostingを利用してホスティング環境をデプロイする

Firebaseでプロジェクトを作成して左メニューからHostingを有効にしておく、あとはコマンドラインから。

まずはFirebas toolsをインストールしておく

npm install -g firebase-tools


まずはログイン

firebase login


以下のように聞かれるのでyesを選択

? Allow Firebase to collect anonymous CLI usage and error report
ing information?


ブラウザが開くのでFirebaseを利用しているGoogleのアカウントを選択しよう。

firebase init


ここでhostingを選択して、Firebaseでプロジェクトが選択できる場合は選択、選択できない場合は[don't setup a default project]を選んでおく ( あとでFirebase use −addコマンドで追加できる

デプロイするディレクトリとすべてのURLのエイリアスを/index.htmlにするSPAモードの選択ができる

? What do you want to use as your public directory? 
? Configure as a single-page app (rewrite all urls to /index.htm
l)?


これで、firebase.jsonファイルと.firebasercファイルが作成される

あとは以下のコマンドでデプロイできるはず

firebase deploy





posted by ねこまんま at 16:29 | テクニック | 更新情報をチェックする

Vue CLIを使ってVueの環境を作成する

まずはvue-cliをグローバルにインストール

npm install -g vue-cli


インストール内容を exec $SHELL -l で反映すればvueコマンドが利用できるので -h オプションでヘルプを表示してみましょう

exec $SHELL -l
vue -h


vue init コマンドでプロジェクトを作成

vue init webpack-simple vue-cli-sample


インストールができたらディレクトリに移動してnpmのインストールと実行を行います

cd vue-cli-sample
npm install
npm run dev


http://localhost:8080/ に移動するとVueプロジェクトが実行されているのを確認できます。

src/App.js のmsgなどを変更するとhttp://localhost:8080/ も変更されるのを確認することができます。

<script>
export default {
name: 'app',
data () {
return {
msg: 'Vue CLIを使ってVueの環境を作成する'
}
}
}
</script>


posted by ねこまんま at 15:32 | テクニック | 更新情報をチェックする

2019年01月12日

FirebaseとNuxt.jsを使ってユーザ認証関係2

FirebaseとNuxt.jsを使ってユーザ認証関係の続き。

前回はメールアドレスとパスワードを入力してアカウントを作成したが、今回はメールアドレス入力→確認メール→認証画面というフローでユーザ認証ができるように変更していきます。
posted by ねこまんま at 13:22 | テクニック | 更新情報をチェックする

2019年01月09日

TypeScriptのreadonly修飾子とReadonly型

TypeScriptではプロパティにreadonly修飾子とつけることで再書き込みができないプロパティを定義することができます。

interface Foo {
readonly prop: string
}
const foo: Foo = {
prop: `ok`
}
foo.prop = `ng` // Error


Classプロパティも同様でreadonly修飾子をつけたものは変更ができない

class Foo {
readonly prop = `ok`
constructor() {
this.prop = `ng` // ng
}
}


また、Readonly型も用意されておりReadonly型にキャストすることで変更不可にすることもできる。

type Foo = {
prop: string
}
type FooReadonly = Readonly<Foo>
const foo: FooReadonly = {
prop: `ok`
}
foo.prop = `ng` // Error


参考: Readonly · TypeScript Deep Dive
posted by ねこまんま at 15:18 | テクニック | 更新情報をチェックする

2018年12月14日

FirebaseとNuxt.jsを使ってユーザ認証関係

via: FirebaseとNuxt.jsを使ってユーザ認証関係を簡単に作ってみる

経験が少ない技術のキャッチアップがてらにサンプルをひたすら写経シリーズ。

初期設定



npx create-nuxt-app nuxt_firebase


でインストールして以下のコマンドで実行

cd nuxt_firebase
npm run dev


これで http://localhost:3000/ にアクセスできます。楽

Firebaseをインストールして

npm install firebase


pluginsの中にfirebase.jsを作成

import firebase from 'firebase'

if (!firebase.apps.length) {
firebase.initializeApp({
apiKey: "API_KEY",
authDomain: "APP_ID.firebaseapp.com",
databaseURL: "https://PROJECT_ID.firebaseio.com",
projectId: "PROJECT_ID",
storageBucket: "PROJECT_ID.appspot.com",
messagingSenderId: "1234567890"
})
}

export default firebase


各種の設定はFirebaseプロジェクトの「ウェブアプリに Firebase を追加」から取得できる。

また、左メニューのAuthenticationよりログイン方法のメール / パスワードを有効にして、サンプルユーザーを作成しておく

ストア設定



export const strict = false

export const state = () => ({
user: null,
})

export const mutations = {
setUser (state, payload) {
state.user = payload
}
}

export const actions = {
setUser ({ commit }, payload) {
commit('setUser', payload)
}
}

export const getters = {
isAuthenticated (state) {
return !!state.user
}
}



ログイン機能




/pages/index.vueを以下のように変更しておく

<template>
<div>
<!-- ログイン中に表示される画面 -->
<div v-if="isAuthenticated">
{{ user.email }}でログイン中です<br>
<button v-on:click="logout">ログアウト</button><br>
<a href="/member-page">メンバーページへ</a>
</div>
<!-- ログインしていない時に表示される画面 -->
<div v-else>
メール<br>
<input type="text" v-model="email"><br>
パスワード<br>
<input type="password" v-model="password"><br>
<button v-on:click="login">ログイン</button>
</div>
</div>
</template>

<script>
import firebase from '~/plugins/firebase'
import { mapActions, mapState, mapGetters } from 'vuex'
export default {
data() {
return {
email: '',
password: ''
}
},
computed: {
...mapState(['user']),
...mapGetters(['isAuthenticated'])
},
mounted() {
firebase.auth().onAuthStateChanged((user) => {
this.setUser(user)
})
},
methods : {
...mapActions(['setUser']),
login() {
firebase.auth().signInWithEmailAndPassword(this.email, this.password)
.then(user => {
// ログインしたら飛ぶページを指定
// this.$router.push("/member-page")
}).catch((error) => {
alert(error)
});
},
logout() {
firebase.auth().signOut()
.then(() => {
this.setUser(null)
}).catch((error) => {
alert(error)
})
}
}
}
</script>


これによりログイン時と未ログイン時に状況を切り替えることができる。

ここまでは参考サイトのほぼ引用。
ここからは独自の内容。

アカウント作成



index.vueにアカウント作成用にページへのURLを追加して

      <button v-on:click="login">ログイン</button>
<p><a href="/register-user">新規会員登録</a></p>
</div>
</div>
</template>


/pages/register-user.vueを以下のように設定する

<template>
<div>
メール<br>
<input type="text" v-model="email"><br>
パスワード<br>
<input type="password" v-model="password"><br>
<p v-if="error_code==='auth/invalid-email'">メールアドレスが不正です</p>
<button v-on:click="registerUser">登録</button>
</div>
</template>

<script>
import firebase from '~/plugins/firebase'
import { mapActions } from 'vuex'
export default {
data() {
return {
email: '',
password: '',
error_code:''
}
},
methods : {
...mapActions(['setUser']),
registerUser() {
firebase.auth().createUserWithEmailAndPassword(this.email, this.password)
.then(user => {
this.setUser({
email:this.email,
password:this.password
})
this.$router.push("/")
})
.catch(error =>{
this.error_code = error.code
});
}
}
}
</script>


これでアカウント作成成功時にはストアにアカウント情報を登録してindexページに遷移、入力内容が不正な場合はエラーをヒュウ視することができる
posted by ねこまんま at 11:54 | テクニック | 更新情報をチェックする

2018年11月15日

TypeScriptのPartial

Partialを利用すると既存の型から、項目を部分的に共有できる型を作成できます。

ちなみにPartialは部分的という意味

たとえば以下のような型があり

interface Foo {
a: string
b: string
c: string
}


aかbかcを含む型を作りたい場合は以下のように定義しなくてはいけないですが、

interface PartialFoo {
a?: string
b?: string
c?: string
}


Partialを利用すると以下のように定義できます。

type PartialFoo = Partial<Foo>


ちなみにPartialの実態は以下のように定義をされています。

type Partial<T> = {
[P in keyof T]?: T[P];
};
posted by ねこまんま at 15:42 | TypeScript | 更新情報をチェックする

2018年11月12日

Jest + enzyme でイベントをシュミレート

Jest + enzyme でイベントをシュミレートをする際によく書く記述をまとめてみました。

describe('コンポーネントのテスト', () => {

it('関数実行されているか', () => {
const mockFun = jest.fn()

const wrapper = shallow(
<MyComonent onChange={mockFun}/>
)

wrapper.find('button').simulate('click');

expect(mockFun).toHaveBeenCalled();

})

it('関数2回実行されているか', () => {
const mockFun = jest.fn()

const wrapper = shallow(
<MyComonent onChange={mockFun}/>
)

wrapper.find('button').simulate('click');

wrapper.find('button').simulate('click');
expect(mockFun)toHaveBeenCalledTimes(2)
})

it('Stateが変わっているか', () => {
const wrapper = shallow(
<MyComonent onChange={mockFun}/>
)

wrapper.find('button').simulate('click');

expect(wrapper.state('clicked')).toBe(true)

})

it('イベントオブジェクトをシュミレート', () => {
const myText = 'dummy text'

const wrapper = shallow(
<MyComonent onChange={mockFun}/>
)

wrapper.find('input').simulate('change',{
currentTarget: {
value: myText
}
});

expect(wrapper.state('text')).toBe(myText)

})

it('関数が特定の引数で実行されているか, () => {
const myText = 'dummy text'

const wrapper = shallow(
<MyComonent onChange={mockFun}/>
)

wrapper.find('input').simulate('change',{
currentTarget: {
value: myText
}
});

expect(wrapper).toHaveBeenCalledWith({
text:myText
})

})

})
タグ:REACT jest ENZYME
posted by ねこまんま at 15:31 | test | 更新情報をチェックする

2018年11月04日

TypeScriptのPick

TypeScriptのPickを利用すると特定の型から特定の項目を抜き出した型を作成することができます。

export enum Gender {
man,
woman,
etc
}

export interface PersonData {
name: string
age: number
gender: Gender
}

const personData: PersonData = {
name: 'yamada tarou',
age: 12,
gender: Gender.man
}


PersonDataにはnameとageとgenderという3つのプロパティが存在しますが、以下のようにPickを利用してnameとageの型を作成できます。

export type SimpleData = Pick<PersonData, 'name' | 'age'>

export const simpleData: SimpleData = {
name: 'yamada tarou',
age: 12
}


export interface CompanyData {
companyName: string
address: string
tell: string
}

型作成時に&でつなげることで複数の型を連結した型を作成することもできます。

export type StaffSimpleData = Pick &
Pick

export const staffSimpleData: StaffSimpleData = {
name: 'yamada tarou',
age: 12,
companyName: 'toyota',
address: '名古屋'
}


特定の型を追加して行くことも可能です。

export type StaffData = Pick &
Pick & {
staffId: number
}

export const StaffData: StaffData = {
name: 'yamada tarou',
age: 12,
companyName: 'toyota',
address: '名古屋',
staffId: 100
}
posted by ねこまんま at 15:24 | TypeScript | 更新情報をチェックする

2018年09月03日

Jest + enzyme でテストを書く

Jest + enzyme でテストを書いていく

まずはJestのインストール

npm install --save-dev jest


npm install --save-dev babel-jest babel-core regenerator-runtime


sum.jsを以下のようにして

export default sum = (a, b) => a + b


同階層にsum.test.jsを配置

import sum  from './sum'

test('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
})


expectで評価したい値を、toBe(X)で値をどう評価したいかを記述する
posted by ねこまんま at 09:58 | テクニック | 更新情報をチェックする

2018年06月30日

TypeScriptのジェネリック

TypeScirptのジェネリックは以下のように関数実行時に型を定義すると関数内で型を利用できる。

function sample1<T>(arg: T): T {
return arg
}
sample1<string>('string')
sample1<number>(1)


型推論が行われるため必ずしも実行時に明示的に型を指定する必要はない

sample1('string')
sample1(1)


関数式の場合は上記のように定義できるけど、関数リテラルの場合か以下のように定義します。

const sample2: { <T>(arg: T): T } = arg => {
return arg
}
sample2<string>('string')
sample2<number>(1)


interfaceを利用して以下のように定義することもできる

interface MyFuncParam<T> {
(arg: string): T
}
interface MyFuncResponse {
type: string
text: string
}
const sample3: MyFuncParam<MyFuncResponse> = text => {
return {
type: 'aaaa',
text
}
}
sample3('foo')
posted by ねこまんま at 01:54 | Comment(0) | TypeScript | 更新情報をチェックする

2018年06月22日

[ts] 'React' は UMD グローバルを参照していますが、現在のファイルはモジュールです。代わりにインポートを追加することを考慮してください。

TypeScript と React で悪戦苦闘していると「[ts] 'React' は UMD グローバルを参照していますが、現在のファイルはモジュールです。代わりにインポートを追加することを考慮してください。」とのエラーが

import { Component } from 'react'


を以下のように変更すると直りました。

import React, { Component } from 'react'
posted by ねこまんま at 12:02 | Comment(0) | React | 更新情報をチェックする

2018年06月13日

Reactでasyncコンポーネントを作成して非同期で読み込みを行う

以下のようなコンポーネントをAsyncComponent.jsなどとして作成
async / awaitを利用して呼び出し時に引数で指定されたコンポーネントの呼び出しを行います。

import React, { Component } from "react";

export default function asyncComponent(importComponent) {
class AsyncComponent extends Component {
constructor(props) {
super(props);

this.state = {
component: null
};
}

async componentDidMount() {
const { default: component } = await importComponent();

this.setState({
component: component
});
}

render() {
const C = this.state.component;

return C ? <C {...this.props} /> : null;
}
}

return AsyncComponent;
}


ルーティング時に呼び出したいコンポーネントを利用できるようにしておきます

render(
<div>
<Provider store={store}>
<ConnectedRouter history={history}>
<div>
<Switch>
<Route
exact
path="/a"
component={asyncComponent(() =>
import('./App1')
)}
/>
<Route
path="/b"
component={asyncComponent(() =>
import('./App2')
)}
/>
<Route
path="/c"
component={asyncComponent(() =>
import('./App3')
)}
/>
<Redirect to="/a" />
</Switch>
</div>
</ConnectedRouter>
</Provider>
</div>,
document.getElementById('root')
);


via : https://serverless-stack.com/chapters/code-splitting-in-create-react-app.html
タグ:async REACT await
posted by ねこまんま at 12:38 | Comment(0) | React | 更新情報をチェックする

Reactのreact-helmet-asyncでhead情報を挿入

react-helmet-asyncを利用するとhead内に様々な情報を挿入できる


import * as React from "react";
import { render } from "react-dom";
import Helmet, { HelmetProvider } from "react-helmet-async";

import Hello from "./Hello";

const styles = {
fontFamily: "sans-serif",
textAlign: "center"
};

const App = () => (
<HelmetProvider>
<div style={styles}>
<Helmet>
<title>Hello World!!</title>
<link rel="canonical" href="https://www.tacobell.com/" />
</Helmet>
<Hello name="CodeSandbox" />
<h2>Start editing to see some magic happen {"\u2728"}</h2>
</div>
</HelmetProvider>
);

render(<App />, document.getElementById("root"));


HelmetProviderで包んでおけばHelmetで包んだ要素内でhead要素に入れることができる
posted by ねこまんま at 01:08 | Comment(0) | React | 更新情報をチェックする

TypeScript + Reactの基本

Propsを定義


iterface Props {
value: number;
}
class Square extends React.Component {}


PropsとStateを定義


iterface Props {
value: number;
}
interface State {
value: number | null;
}
class Square extends React.Component {}

タグ:REACT TypeScript
posted by ねこまんま at 00:59 | Comment(0) | React | 更新情報をチェックする
×

この広告は180日以上新しい記事の投稿がないブログに表示されております。