20190305のReactに関する記事は7件です。

[備忘録]Reactについての個人メモ

React勉強の備忘録

Reactとは

javascriptのライブラリ
DOMの更新とイベントハンドリングをやってくれるライブラリ
MVCのviewの役割だけ
ReactではDOMの更新に仮想DOMを使っている
Reactではコンポーネントという単位でUIパーツを作る

メリット

早い
Reactの書き方がコンポーネント単位だから再利用しやすく保守性が高い

DOMとは

Document Object Model
DOMは文書をノードとオブジェクトで表現し、その文書を表現、保存、操作する方法らしい。

JSX

htmlみたいに書かれているけれど、Babelでコンパイルして使う
Reactのために作られたjavascriptの書き方

Reactを触っていて直感的に理解しにくかったところ

  • PropTypes
  • State
  • 仮想DOM これはまた近いうちに勉強しよう。。

これからまとめたいと思っているところ

  • Reactの基本的な構造?図解したいなー
  • Reactのデプロイ方法一個
  • DOMについて

感想

ざっくり自分用のメモをまとめてみた感じになってしまっていろんなサイトのURLを貼ってしまったけどいいのかなこれ。。
とりあえず、最初から作ってみるのは個人的に気持ち悪かったのであさーく特徴とかさらっとこうかなくらいのメモでした。
次の記事は実際にコード書きながら理解したことを記録していきたいなと

参考
DOMの図
そもそもDOMとは
だいぶ参考になったスライド
Reactチュートリアル日本語訳

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Sass map eachを使って色を指定する

以外と知らない人が多そうなので出力します。
各要素に応じて色を定義している場合があると思います。
例えば信号の状態を表現する以下のようなcssがあります。

.signal-stop {
  color: #dd0000;
}

.signal-caution {
  color: #f4e542;
}

.signal-go {
  color: #5ce053;
}

これをmapを使うと以下のように記述することができます。

$map: (stop: #dd0000, caution: #f4e542, go: #5ce053);

@each $state, $color in $map {
    signal-#{$state} {
        color: $color;
    }
}

例えば、これに信号が停電するような場合を追加する場合は

$map: (stop: #dd0000, caution: #f4e542, go: #5ce053, blackout: #000000 );

とすれば済みそうです。実際のコードでは状態が8つあったので大分スッキリさせることができました。

https://sass-lang.com/documentation/file.SASS_REFERENCE.html#each-multi-assign
https://sass-lang.com/documentation/file.SASS_REFERENCE.html#lists
https://www.sassmeister.com/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【React】超ざっくり入門(Hooks)

概要

React16.8から新しい機能としてHooksが導入されました。
以下の順序でHooksとは何かざっくり入門していきましょう。

Hooksとは?

Hooksとは従来classコンポーネントでしか使用できなかったstate等の機能をfunctionalコンポーネント(関数コンポーネント)でも使用可能にする機能です。

この記事では以下の3種類のhookを紹介します。

  • (1)State Hook:statesetStateを関数コンポーネント内で使用可能にする。
  • (2)Effect Hook:データ取得やDOM変更といったside effectsを関数コンポーネント内で使用可能にする。
  • (3)Custom Hooks:共通のロジックをコンポーネント間での再利用を可能にする。

Hooksの規則

Hooksを使用する際には以下の規則を守りましょう。

  • (1) Hooksは必ずコンポーネント中の一番上(トップレベル)に定義する。(ループ、条件分岐、ネストされた関数の中で定義してはいけません。)
  • (2) HooksはReactの関数コンポーネントの中だけで呼ぶ。(通常のJavascriptの関数から使用してはいけません。)

State Hook

上記で記した様に、statesetStateを関数コンポーネント内で行える様にします。
具体的にはuseStateと呼ばれるhookを使用します。

useStateの使用方法を従来のclassコンポーネントと比較して確認していきます。

従来のclassコンポーネント

以下の例では主に2つの事を行なっています。

  • (1)stateで初期値に0を持つcountを定義する。
  • (2)setStateでボタンを押すたびにcount1を足している。

output2

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  render() {
    return (
      <div>
        <p>{this.state.count} 回クリックしました。</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          クリックしてください。
        </button>
      </div>
    );
  }
}

StateHook

上記と全く同じ事をuseStateを使用して行います。

まずuseStateをインポートしましょう。

import React, { useState } from  'react';

useStateでは従来のstatesetStateを同時に設定します。
以下の3点に注目して以下のコードを見てみましょう。

  • (1) countがclassコンポーネントでいうthis.state={count:0}の部分。
  • (2) setCountがclassコンポーネントでいうsetStateの部分。
  • (3) useState()に渡されている0countの初期値。
import React, { useState } from  'react';

function Counter() {
  const [count, setCount] = useState(0)
}

また以下の2点を踏まえて残りのコードを完成させます。

  • (1) stateを直接参照できる。
  • (2) setCountを使用してstateを更新できる。
import React, { useState } from  'react';

function Counter() {
  const [count, setCount] = useState(0)

  return(
    <div>
      // (1) stateを直接参照できる。
      <p>{count} 回クリックしました</p>

      // (2) setCountを使用してstateを更新できる。
      <button onClick={() => setCount(count + 1)}> クリックしてください。</button> 
    </div>
  )
}

export default Counter;

ちなみに以下の様にして複数のstateを定義していきます。

import React, { useState } from  'react';

function Counter() {
  const [count, setCount] = useState(0)
  const [name, setName] = useState('')

  return(
    <div>
      <p>{count} 回クリックしました</p>
      <button onClick={() => setCount(count + 1)}> クリックしてください。</button>
      <p>私の名前は{name}</p>
      <button onClick={() => setName('テスト太郎')}>名前表示</button>
    </div>
  )
}

export default Counter;

Effect Hook

上記で記した通り、データ取得やDOM変更といったside effectsを関数コンポーネント内で使用可能にします。

従来のclassコンポーネントではcomponentDidMountcomponentDidUpdatecomponentWillUnmount等の中でデータ取得やDOM変更を行なっていましたが、これをuseEffectと呼ばれるhookを使用し、関数コンポーネントでも使用可能にします。

こちらもuseEffectの使用方法を従来のclassコンポーネントと比較して確認していきます。

従来のclassコンポーネント

従来はcomponentDidMountはマウントされた直後に1回だけ呼ばれ、componentDidUpdateはコンポーネントが更新された後に呼ばれ、ここでデータの取得等を行いました。

output3

import React from  'react';

class Effect extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  componentDidMount() {
    console.log('マウントされました。')
  }

  componentDidUpdate() {
    console.log('アップデートされました。')
  }

  render() {
    return (
      <div>
        <h1>{this.state.count} 回クリックしました。</h1>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          クリックしてください。
        </button>
      </div>
    );
  }
}

EffectHook

useEffectは従来のcomponentDidMountcomponentDidUpdatecomponentWillUnmountの3つを組み合わせた様なもので、基本的にrenderされる毎に呼ばれます。(first renderを含む。)
hooksを使用した開発ではここでside effectsを実行します。

output4

import React, { useState, useEffect } from 'react'

function Effect() {
  const [count, setCount] = useState(0)

  useEffect(() => {
    console.log('レンダーされました。')
  })

  return(
    <div>
      <h1>{count} 回クリックしました</h1>
      <button onClick={() => setCount(count + 1)}> クリックしてください。</button>
    </div>
  );
}

Custom Hooks

上記で記載した通り、共通のロジックをコンポーネント間での再利用を可能にします。

以下の2つのコンポーネントがあるとします。

  • (1) 受け取ったid1だったらログイン中ですを返す、status.js
  • (2) 受け取ったid1だったらおかえりなさいを返すmessage.js
status.js
export default function Status(props){
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  const handleStateChange = (id) => {
    if(id === 1){
      setIsLoggedIn(true)
    }
    else{
      setIsLoggedIn(false)
    }
  }

  useEffect(() => {
    handleStateChange(props.user.id)
  })

 const status = isLoggedIn ? 'ログイン中' : 'サインアップ'

  return (
    <>
      <h1>Status: {status}</h1>
    </>
  )
}
message.js
export default function Message(props){
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  const handleStateChange = (id) => {
    if(id === 1){
      setIsLoggedIn(true)
    }
    else{
      setIsLoggedIn(false)
    }
  }

  useEffect(() => {
    handleStateChange(props.user.id)
  })

 const message = isLoggedIn ? 'おかえりなさい' : 'おかえりなさい'

  return (
    <>
      <h1>Message: {message}</h1>
    </>
  )
}

ここの共通したロジック部分をcustom Hookを使用する事で、以下の様に抜き出す事ができます。
抜き出したロジックのコンポーネントはuseから始まる慣習があります。今回はuseLoginと名付けました。

useLogin
import { useState, useEffect } from 'react';

export default function useLogin(userId){
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  // コンポーネント間で再利用したいロジック
  const handleStateChange = (id) => {
    if(id === 1){
      setIsLoggedIn(true)
    }
    else{
      setIsLoggedIn(false)
    }
  }

  // side effectsを実行する。
  useEffect(() => {
    handleStateChange(userId)
  })

  return isLoggedIn;
}

useLoginを使用する事でstatus.jsmessage.jsをよりスッキリ書くことができます。

user.js
import React from 'react';
import useLogin from './useLogin';

export default function Status(props){
  const status = useLogin(props.user.id) ? 'ログイン中' : 'サインアップ'
  return (
    <>
      <h1>Status: {status}</h1>
    </>
  )
}
message.js
import React from 'react';
import useLogin from './useLogin';

export default function Message(props){
  const message = useLogin(props.user.id) ? 'おかえりなさい' : 'サインアップしてください'
  return (
    <>
      <h1>Message: {message}</h1>
    </>
  )
}

custom hooksでは他にも色々な事ができるので、詳細は公式ドキュメントで確認ください。

参照

hooksの説明としては本当にざっくりでしたので、詳細は公式ドキュメントで確認ください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【React】ざっくり入門(Hooks)

概要

React16.8から新しい機能としてHooksが導入されました。
以下の順序でHooksとは何かざっくり入門していきましょう。

Hooksとは?

Hooksとは従来classコンポーネントでしか使用できなかったstate等の機能をfunctionalコンポーネント(関数コンポーネント)でも使用可能にする機能です。

この記事では以下の3種類のhookを紹介します。

  • (1)State Hook:statesetStateを関数コンポーネント内で使用可能にする。
  • (2)Effect Hook:データ取得やDOM変更といったside effectsを関数コンポーネント内で使用可能にする。
  • (3)Custom Hooks:共通のロジックをコンポーネント間での再利用を可能にする。

Hooksの規則

Hooksを使用する際には以下の規則を守りましょう。

  • (1) Hooksは必ずコンポーネント中の一番上(トップレベル)に定義する。
  • ループ、条件分岐、ネストされた関数の中で定義してはいけません。)
  • (2) HooksはReactの関数コンポーネントの中だけで呼ぶ。(通常のJavascriptの関数から使用してはいけません。)

State Hook

useStateと呼ばれるhookを使用する事でstatesetStateを関数コンポーネント内で行える様にします。
classコンポーネントuseStateを使用した関数コンポーネントを比較して使用方法を確認して見ましょう。

従来のclassコンポーネント

以下の例では主に2つの事を行なっています。

  • (1)stateで初期値に0を持つcountを定義する。
  • (2)setStateでボタンを押すたびにcount1を足している。

output2

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  render() {
    return (
      <div>
        <p>{this.state.count} 回クリックしました。</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          クリックしてください。
        </button>
      </div>
    );
  }
}

StateHook

上記と全く同じ事をuseStateを使用して行います。
基本的な使用方法(定義方法)は以下の通りです。

const [state, setState] = useState(initialState);

useStateでは従来のstatesetStateを同時に設定しする様なイメージです。
上記のcountやそのsetStateuseStateを使用して定義すると以下の様になります。

import React, { useState } from  'react';

function Counter() {
  const [count, setCount] = useState(0)
}

以下の3点に注目して上のコードを見てみましょう。

  • (1) countがclassコンポーネントでいうthis.state={count:0}の部分。
  • (2) setCountがclassコンポーネントでいうsetStateの部分。
  • (3) useState()に渡されている0countの初期値。

また以下の2点を踏まえて残りのコードを完成させます。

  • (1) stateを直接参照できる。
  • (2) setCountを使用してstateを更新できる。
import React, { useState } from  'react';

function Counter() {
  const [count, setCount] = useState(0)

  return(
    <div>
      // (1) stateを直接参照できる。
      <p>{count} 回クリックしました</p>

      // (2) setCountを使用してstateを更新できる。
      <button onClick={() => setCount(count + 1)}> クリックしてください。</button> 
    </div>
  )
}

export default Counter;

ちなみに以下の様にして複数のstateを定義していきます。

import React, { useState } from  'react';

function Counter() {
  const [count, setCount] = useState(0)
  const [name, setName] = useState('')

  return(
    <div>
      <p>{count} 回クリックしました</p>
      <button onClick={() => setCount(count + 1)}> クリックしてください。</button>
      <p>私の名前は{name}</p>
      <button onClick={() => setName('テスト太郎')}>名前表示</button>
    </div>
  )
}

export default Counter;

Effect Hook

従来のclassコンポーネントではcomponentDidMountcomponentDidUpdatecomponentWillUnmount等の中でデータ取得やDOM変更を行なっていましたが、これをuseEffectと呼ばれるhookを使用し、関数コンポーネントでも使用可能にします。

こちらもuseEffectの使用方法を従来のclassコンポーネントと比較して確認していきます。

従来のclassコンポーネント

従来はcomponentDidMountはマウントされた直後に1回だけ呼ばれ、componentDidUpdateはコンポーネントが更新された後に呼ばれ、ここでデータの取得等を行いました。

output3

import React from  'react';

class Effect extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  componentDidMount() {
    console.log('マウントされました。')
  }

  componentDidUpdate() {
    console.log('アップデートされました。')
  }

  render() {
    return (
      <div>
        <h1>{this.state.count} 回クリックしました。</h1>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          クリックしてください。
        </button>
      </div>
    );
  }
}

EffectHook

useEffectは従来のcomponentDidMountcomponentDidUpdatecomponentWillUnmountの3つを組み合わせた様なもので、基本的にrenderされる毎に呼ばれます。(first renderを含む。)
hooksを使用した開発ではここでside effectsを実行します。

output4

import React, { useState, useEffect } from 'react'

function Effect() {
  const [count, setCount] = useState(0)

  useEffect(() => {
    console.log('レンダーされました。')
  })

  return(
    <div>
      <h1>{count} 回クリックしました</h1>
      <button onClick={() => setCount(count + 1)}> クリックしてください。</button>
    </div>
  );
}

Custom Hooks

上記で記載した通り、共通のロジックをコンポーネント間での再利用を可能にします。

以下の2つのコンポーネントがあるとします。

  • (1) 受け取ったid1だったらログイン中ですを返す、status.js
  • (2) 受け取ったid1だったらおかえりなさいを返すmessage.js
status.js
export default function Status(props){
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  const handleStateChange = (id) => {
    if(id === 1){
      setIsLoggedIn(true)
    }
    else{
      setIsLoggedIn(false)
    }
  }

  useEffect(() => {
    handleStateChange(props.user.id)
  })

 const status = isLoggedIn ? 'ログイン中' : 'サインアップ'

  return (
    <>
      <h1>Status: {status}</h1>
    </>
  )
}
message.js
export default function Message(props){
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  const handleStateChange = (id) => {
    if(id === 1){
      setIsLoggedIn(true)
    }
    else{
      setIsLoggedIn(false)
    }
  }

  useEffect(() => {
    handleStateChange(props.user.id)
  })

 const message = isLoggedIn ? 'おかえりなさい' : 'あなたは誰ですか?'

  return (
    <>
      <h1>Message: {message}</h1>
    </>
  )
}

ここの共通したロジック部分をcustom Hookを使用する事で、以下の様に抜き出す事ができます。
抜き出したロジックのコンポーネントはuseから始まる慣習があります。今回はuseLoginと名付けました。

useLogin
import { useState, useEffect } from 'react';

export default function useLogin(userId){
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  // コンポーネント間で再利用したいロジック
  const handleStateChange = (id) => {
    if(id === 1){
      setIsLoggedIn(true)
    }
    else{
      setIsLoggedIn(false)
    }
  }

  // side effectsを実行する。
  useEffect(() => {
    handleStateChange(userId)
  })

  return isLoggedIn;
}

useLoginを使用する事でstatus.jsmessage.jsをよりスッキリ書くことができます。

user.js
import React from 'react';
import useLogin from './useLogin';

export default function Status(props){
  const status = useLogin(props.user.id) ? 'ログイン中' : 'サインアップ'
  return (
    <>
      <h1>Status: {status}</h1>
    </>
  )
}
message.js
import React from 'react';
import useLogin from './useLogin';

export default function Message(props){
  const message = useLogin(props.user.id) ? 'おかえりなさい' : 'サインアップしてください'
  return (
    <>
      <h1>Message: {message}</h1>
    </>
  )
}

custom hooksでは他にも色々な事ができるので、詳細は公式ドキュメントで確認ください。

参照

hooksの説明としては本当にざっくりでしたので、詳細は公式ドキュメントで確認ください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Jestのスナップショットテストを導入してみる

?初心者です。

社内で運用しているアプリケーションがReact.jsを使っているので、Jestが用意しているスナップショットテストを導入することにしました!

【導入のきっかけ】

現在進行形で既にあるアプリケーションのバグを対応することになりました。
ブラウザバックすると予期せぬコンポーネントでエラーになってしまい、結果画面真っ白になってしまうとか…
共通のヘッダーコンポーネントを修正しなければならなそうで、もし1行変えただけで全体に影響を及ぼしてしまったら…? スナップショットが入っていれば、1行対応した後にテストコマンド一つでスナップショットの差分が分かり、どこが変わったか一発で分かります!
スナップショットもGitで管理すると良いです☺️

【まずは下準備】

必要なライブラリをインストールしておきます。

$ yarn add -D babel-jest enzyme enzyme-adapter-react-16 react-test-renderer

importしているコンポーネントのパスがエイリアスになっているので、そこも解消するべくpackage.jsonに追記します。今回はエイリアス@app/***/***用に下のような記述をしています。

{
  ...
  "jest": {
    "moduleNameMapper": {
      "^@app(.*)$": "<rootDir>/src/app$1"
    },
    "verbose": true,
    "setupFiles": [
      "<rootDir>/setupTests.js"
    ],
    "moduleFileExtensions": [
      "js",
      "json",
      "jsx"
    ]
  }
  ...
}

↑ 参考:Solve Module Import Aliasing for Webpack, Jest, and VSCode

setupTests.jsの内容はこちらです!
enzymeの指定をしており、packge.jsonのsetupFilesで読み込ませています。

import Enzyme from 'enzyme'
import EnzymeAdapter from 'enzyme-adapter-react-16'

Enzyme.configure({
  adapter: new EnzymeAdapter(),
  disableLifecycleMethods: true,
})

【いざ、実践!】

やり方は公式サイトを参考に始めます。

公式 Snapshot Testing

今回実装するきっかけになったヘッダーコンポーネントから実装してみます!
公式サイトを見る限り簡単そう。?
余裕でしょ!笑

一番最初に書いた記述がこちら!

■失敗その1

import React from 'react'
import renderer from 'react-test-renderer'
import { CommonHeader } from 'Components/Common/Header'

describe('<CommonHeader />', () => {
  it('スナップショット', () => {
    const tree = renderer
      .create(<CommonHeader />)
      .toJSON()
    expect(tree).toMatchSnapshot()
  })
})

これでは上手くいかず、こんなエラーが表示されました。

TypeError: this.props.handleFetchUser is not a function

コンポーネントでは、handleFetchUsermapDispatchToPropsで呼び出しています。
propsを渡せていないことによるエラーが他に1つ出ていたので、こちらを解消します!

■失敗その2

describe('<CommonHeader />', () => {
  it('スナップショット', () => {
    const props = {
      match: {},
      handleFetchUser: jest.fn()
    }
    const tree = renderer.create(<CommonHeader {...props} />).toJSON()
    expect(tree).toMatchSnapshot()
  })
})

エラーになっていたpropsを最初に指定してあげ、<CommonHeader />に渡してあげています。

ですが、今度はこんなエラーが出てしまいました!

Warning: Failed context type: The context `router` is marked as required in `Link`, but its value is `undefined`.
Invariant Violation: You should not use <Link> outside a <Router>

というわけで<CommonHeader /><Router />で囲ってあげましょう!

■ 完成形

import { BrowserRouter as Router } from 'react-router-dom'

describe('<CommonHeader />', () => {
  it('スナップショット', () => {
    const props = {
      match: {},
      handleFetchUser: jest.fn()
    }
    const tree = renderer
      .create(
        <Router>
          <CommonHeader {...props} />
        </Router>
      )
      .toJSON()
    expect(tree).toMatchSnapshot()
  })
})

成功だ!と思ったら、console.warnの文字が…
全部緑色の方が清々しいので、このエラーについてググってみました。
対応策の中でこれかな…と思うものがあったのですが、今回は目をつぶり、保留とさせていただきます。?

↓ 見当違いだったらごめんなさい。
babel-jest does not transpile import/export in node_modules when Babel 7 is used #6229

■ react-routerでpathの判定をしていた時

上記はpropsで渡していますが、stach overflowを見ていたら、下のような記述でも行けるようです。

const matchURL = {
  params: {},
  isExact: true,
  path: "",
  url: ""
}
<CommonHeader match={matchURL} />

余談

実はこのエラーの前に一つ、ヘッダーの中で非同期通信させています。
そこでenvファイルで管理している値を、process.envのように使っており、
最初は「process.env.DUMMY_NAMEがありません」と怒られました。
「なんじゃこりゃ!」と思いましたが、このプロジェクトの場合のみpackage.jsonでローカルと同じenvファイルを呼び出したらいけました?

テストにパスしたので正常に「__snapshots__/index.test.js.snap」ファイルが生成されてくれました…っ!

余談パート2

enzymeのshallowみたいな書き方もできることを知りました!
公式サイトを見ると、
react-test-rendererには、ShallowRendererというのがに用意されているようです。(使ってみたら、上の記述とは違うsnapshotが吐き出されたので、今回は使用しませんでした。)

参考)公式サイト Shallow Renderer

■ さらにさらに

「コンポーネントにsetStateさせた状態でスナップショット撮りたいなぁ…」を叶えてくれるライブラリが紹介されていたので、こちらを採用しました!
enzyme-to-json」を使用しています。
enzymeのshallowを使って色々操作した後、toJsonでwrapperを囲ってスナップショットをしてあげれば出来上がりです!

expect(toJson(wrapper)).toMatchSnapshot();

試しに、setStateでタイトルを指定して、スナップショットの結果が正しく変わってくれるか検証してみました。

import React from 'react'
import { shallow } from 'enzyme'
import renderer from 'react-test-renderer'
import toJson from 'enzyme-to-json'
import { CommonHeader } from 'Components/Common/Header'

const initialProps = {
  ...
}
const setup = (state = {}, props = initialProps) => {
  const wrapper = shallow(<CommonHeader {...props} />)
  return wrapper
}

describe('<CommonHeader />', () => {
  it('プロジェクト名がH1に表示される', () => {
    const wrapper = setup()
    wrapper.setState({
      projectName: 'ダミープロジェクト'
    })
    expect(wrapper.find('h1').text()).toEqual('ダミープロジェクト') // PASS
    expect(toJson(wrapper)).toMatchSnapshot()
  })
})

enzyme-to-jsonの参考になったサイトはこちらです。
6. Testing react components using Jest and Enzyme

スナップショットの結果もsetStateする前後でちゃんと変わってくれました!

【参考にしたサイト】

React Component テストを書くための考え方

What and How to Test with Jest and Enzyme. Full Instruction on React Components Testing

補足

スナップショットの記述を変えてテストを実行していくと、「上書きされた」とエラーが表示されます。
今はゴリゴリテストを実装していくフェーズなので、testの後に-uをつけて実行しましょう!

$ yarn test -u

上書きされてテストがパスされていることが確認できます。

【終えて】

参考にしたのはやはりYoutubeとUdemyです!(動画わかりやすくて感覚派の私には最高!笑)
さらに理解を深めたいので、他コンポーネントでもスナップショットテストを書いていきます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【React】超ざっくり入門(Hooks)

概要

React16.8から新しい機能としてHooksが導入されました。
以下の順序でHooksとは何かざっくり入門していきましょう。

Hooksとは?

Hooksとは従来classコンポーネントでしか使用できなかったstate等の機能をfunctionalコンポーネントでも使用可能にするReactに導入された新しい機能です。

この記事では以下の2種類のhookを紹介します。

  • (1)State Hook:statesetStateをfunctionalコンポーネント内で使用可能にする。
  • (2)Effect Hook:データ取得やDOM変更といったside effectsをfunctionalコンポーネント内で使用可能にする。

Hooksの規則

Hooksを使用する際には以下の規則を守りましょう。

  • (1) Hooksは必ずfunctionalコンポーネント中の一番上(トップレベル)に定義する。(ループ、条件分岐、ネストされた関数の中で定義してはいけません。)
  • (2) HooksはReactのfunctionalコンポーネントの中だけで呼ぶ。(通常のJavascriptの関数から使用してはいけません。)

State Hook

上記で記した様に、statesetStateをfunctionalコンポーネント内で行える様にします。
具体的にはuseStateと呼ばれるhookを使用します。

useStateの使用方法を従来のclassコンポーネントと比較して確認していきます。

従来のclassコンポーネント

以下の例では主に2つの事を行なっています。

  • (1)stateで初期値に0を持つcountを定義する。
  • (2)setStateでボタンを押すたびにcount1を足している。

output2

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  render() {
    return (
      <div>
        <p>{this.state.count} 回クリックしました。</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          クリックしてください。
        </button>
      </div>
    );
  }
}

StateHook

上記と全く同じ事をuseStateを使用して行います。

まずuseStateをインポートしましょう。

import React, { useState } from  'react';

useStateでは従来のstate(ここではcount)とsetStateを同時に定義します。
以下の2点に注目して以下のコードを見てみましょう。

  • (1) 以下のsetCountがclassコンポーネントでいうsetStateの部分。
  • (2) useState()に渡されている0countの初期値。
import React, { useState } from  'react';

function Counter() {
  const [count, setCount] = useState(0)
}

また以下の2点を踏まえて残りのコードを完成させます。

  • (1) stateを直接参照できる。
  • (2) setCountを使用してstateを更新できる。
import React, { useState } from  'react';

function Counter() {
  const [count, setCount] = useState(0)

  return(
    <div>
      // (1) stateを直接参照できる。
      <p>{count} 回クリックしました</p>

      // (2) setCountを使用してstateを更新できる。
      <button onClick={() => setCount(count + 1)}> クリックしてください。</button> 
    </div>
  )
}

export default Counter;

ちなみに以下の様にして複数のstateを定義していきます。

import React, { useState } from  'react';

function Counter() {
  const [count, setCount] = useState(0)
  const [name, setName] = useState('')

  return(
    <div>
      <p>{count} 回クリックしました</p>
      <button onClick={() => setCount(count + 1)}> クリックしてください。</button>
      <p>私の名前は{name}</p>
      <button onClick={() => setName('テスト太郎')}>名前表示</button>
    </div>
  )
}

export default Counter;

Effect Hook

上記で記した通り、データ取得やDOM変更といったside effectsをfunctionalfunctionコンポーネント内で使用可能にします。

従来のclassコンポーネントではcomponentDidMountcomponentDidUpdatecomponentWillUnmount等の中でデータ取得やDOM変更を行なっていましたが、これをuseEffectと呼ばれるhookを使用し、functionalコンポーネントでも使用可能にします。

こちらもuseEffectの使用方法を従来のclassコンポーネントと比較して確認していきます。

従来のclassコンポーネント

従来はcomponentDidMountはマウントされた直後に1回だけ呼ばれ、componentDidUpdateはコンポーネントが更新された後に呼ばれ、ここでデータの取得等を行いました。

output3

import React from  'react';

class Effect extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  componentDidMount() {
    console.log('マウントされました。')
  }

  componentDidUpdate() {
    console.log('アップデートされました。')
  }

  render() {
    return (
      <div>
        <h1>{this.state.count} 回クリックしました。</h1>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          クリックしてください。
        </button>
      </div>
    );
  }
}

EffectHook

useEffectは従来のcomponentDidMountcomponentDidUpdatecomponentWillUnmountの3つを組み合わせた様なもので、基本的にrenderされる毎に呼ばれます。(first renderを含む。)
hooksを使用した開発ではここでside effectsを実行します。

output4

import React, { useState, useEffect } from 'react'

function Effect() {
  const [count, setCount] = useState(0)

  useEffect(() => {
    console.log('レンダーされました。')
  })

  return(
    <div>
      <h1>{count} 回クリックしました</h1>
      <button onClick={() => setCount(count + 1)}> クリックしてください。</button>
    </div>
  );
}

参照

hooksの説明としては本当にざっくりでしたので、詳細は公式ドキュメントで確認ください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

はじめてのcreate-react-app

最終目標

フロントエンドとバックエンドのDB排他を調べてみたい。

今回の目標

Using React in Visual Studio Code の内容を実施する。
https://code.visualstudio.com/docs/nodejs/reactjs-tutorial

OS環境

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 18.04.2 LTS
Release:        18.04
Codename:       bionic

開発環境構築

$ sudo apt update
$ sudo apt upgrade -y
$ sudo reboot
$ sudo apt install nodejs
$ node -v
v8.10.0
$ sudo apt install npm
$ npm -v
3.5.2

React環境構築

$ sudo npm install -g create-react-app
$ create-react-app --version
2.1.5

Reactアプリ作成

$ create-react-app my-app
$ cd my-app/
$ npm start

外部アクセスのためポートを開放する場合(必要に応じて)

$ sudo ufw allow ssh
$ sudo ufw allow 3000

Hello World!

src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

-ReactDOM.render(<App />, document.getElementById('root'));
+var element = React.createElement('h1', { className: 'greeting' }, 'Hello, world!');
+ReactDOM.render(element, document.getElementById('root'));

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: http://bit.ly/CRA-PWA
serviceWorker.unregister();

感想

  • モダンな開発スタイルのような気がする
  • 次は、MERN Starterを調べてみたい
  • AngularとVueも調べてみたい
  • TypeScriptも調べてみたい

以上

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む