20200421のReactに関する記事は4件です。

react-redux-firebase を導入しようとしたときに起きた@@reactReduxFirebase/LOGINのエラーを消したメモ

概要

  • react-redux-firebase を使ってCRUD を試してみた
    • 一応動いた。。。が、使いこなせてない感。
  • そのまま導入すると、以下のエラーが発生。
index.js:1 A non-serializable value was detected in an action, in the path: `auth`. Value: 

Take a look at the logic that dispatched this action:  {type: "@@reactReduxFirebase/LOGIN", auth: P, preserve: undefined} 
  • 以下のようにgetDefaultMiddlewareのオプションを指定することででエラーを消すことができた。
import {
  configureStore,
  getDefaultMiddleware,
  EnhancedStore,
} from '@reduxjs/toolkit'
import { rootReducer } from './rootState'
import logger from 'redux-logger'

export const setupStore = (): EnhancedStore => {
  const middlewares = [
    ...getDefaultMiddleware({
+      serializableCheck: {
+        ignoredActions: ['@@reactReduxFirebase/LOGIN'],
+      },
    }),
  ]

CRUD追加時のソース

参考

React + Redux + Firebase を使ってログイン機能あり掲示板アプリ開発②
Docker で zeit nowのデプロイ環境とNext.jsの開発環境を作ったメモ
PdfMakeを使ったPDF作成APIをZeit Nowで動かしたメモ
react-redux-firebase
react-redux-firebase useFirestore.md
error @@login
firestore
Zeit Now + Next.js のページにFirebase認証を導入した際、環境変数にハマったメモ

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

React×GoでTodoリスト作ってみた

基本の復習も兼ねてTodoリストを作りました。
Reactでは、非同期でHTTP通信を行うためにaxiosを使っています。
Goでは、GORMechoを使っています。

React

Todo.js
import React from 'react';
import InputField from './InputField';
import List from './List';
import http from './http';

class Todo extends React.Component {
  constructor() {
    super();
    this.state = {
      text: "",
      lists: [],
    }
  }

  componentDidMount() {
    this.getTodoList();
  }

  getTodoList = () => {
    return http
      .get('/todo')
      .then((response) => {
        this.setState({ lists: response.data })
      })
      .catch(error => {
        console.log(error)
      })
  }

  handleChange = e => {
    this.setState({ text: e.target.value })
  }

  handleSubmit = () => {
    if (this.state.text === "") {
      return window.alert("入力してください")
    }
    return http
      .post('/todo', {
        text: this.state.text
      })
      .then(() => {
        this.setState({ text: "" });
        this.getTodoList();
      }
      )
      .catch(error => {
        console.log(error)
      })
  }

  handleDelete = (list) => {
    return http
      .delete(`/todo/${list.id}`)
      .then(() =>
        this.getTodoList()
      )
      .catch(error => {
        console.log(error)
      })
  }

  render() {
    return (
      <div className="todo">
        <div className="todo-title">
          <h1>Todo</h1>
        </div>
        <InputField
          text={this.state.text}
          handleChange={this.handleChange}
          handleSubmit={this.handleSubmit}
        />
        <List
          lists={this.state.lists}
          handleDelete={this.handleDelete}
        />
      </div>
    )
  }
}

export default Todo;
InputField.js
import React from 'react';

export default function InputField(props) {
  return (
    <div className="todo-input-field">
      <input placeholder="入力しよう" value={props.text} onChange={e => props.handleChange(e)}></input>
      <button onClick={props.handleSubmit}>保存</button>
    </div>
  )
}
http.js
import axios from 'axios';

const API_HOST = process.env.REACT_APP_API_HOST || 'http://localhost:〇〇〇〇';

const http = axios.create({
  baseURL: API_HOST,
});

export default http;

Go

main.go
package main

import (
    "context"
    "fmt"
    "log"
    "net/http"
    "os"
    "os/signal"

    "パスに合わせて他のパッケージをimport"

    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
)

const defaultPort = "〇〇〇〇"

func port() string {
    p := os.Getenv("PORT")
    if p != "" {
        return ":" + p
    }
    return ":" + defaultPort
}

func main() {
    connStr := fmt.Sprintf(
        "%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True",
        "DBUSER",
        "DBPASSWORD",
        "DBPROTOCOL",
        "DBNAME",
    )

    db, err := gorm.Open("mysql", connStr)
    if err != nil {
        log.Fatal(err)
    }

    h := handler.New(db)

    server := &http.Server{
        Addr:    port(),
        Handler: h,
    }

    go func() {
        stop := make(chan os.Signal, 1)
        signal.Notify(stop, os.Interrupt)

        <-stop
        log.Println("Shutting down...")

        if err := server.Shutdown(context.Background()); err != nil {
            log.Println("Unable to shutdown:", err)
        }

        log.Println("Server stopped")
    }()

    log.Println("Listening on http://localhost" + port())
    if err := server.ListenAndServe(); err != http.ErrServerClosed {
        log.Fatal(err)
    }
}
handler.go
package handler

import (
    "net/http"

    "github.com/jinzhu/gorm"
    "github.com/labstack/echo"
    "github.com/labstack/echo/middleware"
)

func New(db *gorm.DB) http.Handler {
    e := echo.New()
    e.Use(middleware.CORS())

    h := &handler{
        DB: db,
    }

    e.GET("/health", h.health)

    e.GET("/todo", h.getTodoLists)
    e.POST("/todo", h.createTodo)
    e.DELETE("/todo/:id", h.deleteTodo)

    return e
}

type handler struct {
    DB *gorm.DB
}

func (h *handler) health(c echo.Context) error {
    return c.JSON(http.StatusOK, map[string]string{"message": "OK"})
}
list.go
package handler

import (
    "net/http"
    "time"

    "github.com/labstack/echo"
)

type List struct {
    ID        uint      `json:"id"`
    Text      string    `json:"text"`
    CreatedAt time.Time `json:"createdAt"`
    UpdatedAt time.Time `json:"updatedAt"`
}

func (h *handler) getTodoLists(c echo.Context) error {
    var lists []List
    err := h.DB.Find(&lists).Error
    if err != nil {
        return err
    }

    return c.JSON(http.StatusOK, lists)
}

func (h *handler) createTodo(c echo.Context) error {
    var list List
    err := c.Bind(&list)
    if err != nil {
        return err
    }

    err = h.DB.Create(&list).Error
    if err != nil {
        return err
    }

    return c.JSON(http.StatusOK, list)
}

func (h *handler) deleteTodo(c echo.Context) error {
    var list List
    paramID := c.Param("id")

    err := h.DB.Where("id=?", paramID).Delete(&list).Error
    if err != nil {
        return err
    }

    return c.JSON(http.StatusOK, list)
}

本来であれば、type ~ struct 構造体を他のパッケージからインポートするのがベストな気がするのですが、importがうまくできなかったので、list.goにまとめて書きました。
この問題は解決したい、、、

DB

todoというデータベースの中にlistsテーブルがあり、中身は画像のようになってます。
スクリーンショット 2020-04-21 20.25.13.png

Todoリスト

スクリーンショット 2020-04-21 20.29.37.png

このような形で簡単なTodoリストが作成できると思います。

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

Gatsby+microCMSで手を打つ

Gatsby+microCMSで手を打つ

Intro

Angular…、そしてNext.js…。
SPAを開発しているのにSSRを考えないとイカン…なことが多くAngularから流れてくる人多いと思う。そんなこともあってNext.jsを始めたがページリロードすると404エラーとか…、それを解決するのにFunctionをとか導入して関数を書いてサーバー側で…とかもういいかげんにしてと思ってきた。
Nuxtにするか、とまた本買ってしまったが調べてみるとこれでもどうも同じことになるようで無駄な出費またまたあーもーとかなってるところにGatsbyって来て、情報が少ないものの「URLを直叩きしようがリロードしようが、404エラーが帰ってくることはなくなります」(Reactの最強フレームワークGatsby.jsの良さを伝えたい!!
ということなので賭けてみる。

Gatsbyプロジェクト作成

  1. node インストール
  2. git インストール
  3. gatsby-cli インストール
    npm install --global gatsby-cli
  4. プロジェクト作成
    gatsby new <プロジェクト名> (gatsby-default-starterがあたる)
  5. プロジェクトフォルダに移動してローカル環境立ち上げ
    gatsby develop
  6. http://localhost:8000 にアクセス
    image.png

フォルダ構造をみてみる。
image.png
とってもNextと似ているのでつい最近の苦労は無駄でなかったと救われる。
gatsby-config.jsというファイルがプラグイン管理
その他のgatsby-ほにゃらら.jsファイルはデフォルトでカラ。

package.jsonを見てみる

{
  "name": "gatsby-starter-default",
  "private": true,
  "description": "A simple starter to get up and developing quickly with Gatsby",
  "version": "0.1.0",
  "author": "Kyle Mathews <mathews.kyle@gmail.com>",
  "dependencies": {
    "gatsby": "^2.20.12",
    "gatsby-image": "^2.3.1",
    "gatsby-plugin-manifest": "^2.3.3",
    "gatsby-plugin-offline": "^3.1.2",
    "gatsby-plugin-react-helmet": "^3.2.2",
    "gatsby-plugin-sharp": "^2.5.3",
    "gatsby-source-filesystem": "^2.2.2",
    "gatsby-transformer-sharp": "^2.4.3",
    "prop-types": "^15.7.2",
    "react": "^16.12.0",
    "react-dom": "^16.12.0",
    "react-helmet": "^6.0.0"
  },
  "devDependencies": {
    "prettier": "2.0.4"
  },
・・・以下略・・・

reactから派生したんだなとわかる。

microCMSとの連携

ヘッドレスCMSはmicroCMSが評判が良いようなのでこれで。

  1. microCMS用のプラグインをインストールする。
$ yarn add gatsby-source-microcms
  1. つぎに gatsby-config.jsを編集する
・・・前略・・・
    `gatsby-plugin-sharp`,
    {
      resolve: `gatsby-plugin-manifest`,
      options: {
        name: `gatsby-starter-default`,
        short_name: `starter`,
        start_url: `/`,
        background_color: `#663399`,
        theme_color: `#663399`,
        display: `minimal-ui`,
        icon: `src/images/gatsby-icon.png`, // This path is relative to the root of the site.
      },
    },
// 追加↓
    {
      resolve: "gatsby-source-microcms",
      options: {
        apiKey: "X-API-KEY",
        serviceId: "guitar-club",
        endpoint: "news",
      },
    },
// 追加↑
  ],
}

micorCMSのAPI-KEY, サービスID、エンドポイントをoptions:{...}に書けばよいようである。書かないでgatsby developしてもエラーでたち上がらない。

なのでmicroCMSの設定を。

microCMS準備

microCMSのサイトはこちら→ https://microcms.io/
ここでアカウント作成してログイン。
ここでは医療系情報サイトをイメージして、一般情報、患者さん向け、医師向け、といったカテゴリーがあり、それぞれのカテゴリーに多くの情報ページがぶらさがる単純な2階層のWebサイトをイメージして作ってみる。

まずはサービス名とサービスIDを入力。サービスIDはエンドポイントのサブドメインになる(※ https://<サービス名>.microcms.io/ となる)。自分のプロジェクト名とかサイト名がいいだろうわかりやすいし。たとえばhogehoge.jpというサイトだったらhogehogeとか。
image.png

次にコンテンツを作成する。まずはカテゴリーというAPIを作る。左端メニューの「コンテンツ ✙」の✙をクリック。
image.png

カテゴリー、categoryと入力
image.png

リスト形式をえらぶ
image.png

スキーマをつくる。
image.png

追加する、をクリック
image.png

患者向けカテゴリーとしてpatientsと入力した。公開ボタンをクリック
image.png

ほかのカテゴリーも同様に追加していく。ここでは医師向けとしてdoctors、一般情報としてbasicsと。
image.png

次にカテゴリーの下にぶらさげるコンテンツを作っていく。
またコンテンツ✙をクリックして、記事コンテンツ、articlesと入力
image.png

リスト形式を選択
image.png

スキーマをつくっていく。このように。
image.png

種類とあるが、だいたい良く知ったようなものだ。テキストフィールドとかテキストエリアとか。ブログみたくリッチに編集したかったらリッチエディタで画像やリンクを張ったりもできる。カラーピッカーはまだないようだが・・・
image.png

最後にカテゴリーフィールドをつくる。種類は「複数コンテンツ参照」というのを選び、さっき作った「カテゴリー」APIを選んで決定。
image.png

作成できたら、APIリファレンスをクリックしてみる。
image.png

GET /articles/{CONTENT_ID}とあるが、つまりエンドポイントはhttps://<サービスID>.microcms.io/api/v1/articles/になる。gatsbyの場合、gatsby-config.jsのendpoint:に"articles"とだけ書けばいいが、Next.jsなどではgetInitialProps()で

const res = await axios.get(`https://<サービスID>.microcms.io/api/v1/articles/`,
key
)

のようにしなければならないようである。参考:Next.js + microCMS + NetlifyでJAMstackな世界に入門する

APIキーもここに載ってる。表示ボタンをクリックして表示させてコピーして使う。


次にAPI設定をクリック。
image.png

ここでさっき作ったフィールドを削除、追加、編集できる。なので最初は適当にタイトルとか内容(コンテンツ)とかとかまあ適当に・・・
image.png

あとはブログみたく中身をいれるだけ。入力したら公開をクリック。
image.png

「カテゴリー」フィールドは患者さん向けのpatientsにした(入力するときpatients, doctors, basicsから選ぶ)。「紹介アイコン」フィールドは種類を「画像」にしたpictというフィールドである。
image.png

このようにして、カテゴリーpatientsの記事を2つ作ってみた。
患者さん向け記事①
患者さん向け記事②
image.png

ではコーディング

各記事紹介ページを作成

まずはgatsby-config.jsにAPI、サービスID、エンドポイントを設定。
image.png

pagesの下にpatients.jsを作成、以下のようにコード。

// pages/patient.js
import React from "react"
import { graphql } from "gatsby"

import Layout from "../components/layout"
import SEO from "../components/seo"


const PatientsPage = ({ data }) => (
 <Layout>
   <SEO title="患者の方へ" />

   {data.allMicrocmsArticles.edges.map(edge => {
     const articles = edge.node
     const category = edge.node.category[0].name
     console.log('◆categoryは ' + category)

     if (category == 'patients') {      //カテゴリーが患者さん用の場合表示
       return (
        <React.Fragment key={articles.id}>
         <div>
             <h2>{articles.title}</h2>
             <p>{articles.feature}</p>
           <img
             src={articles.pict.url}
             width={110}
             height={110}
             alt="pict画像"
           />
         </div>
         <div>
             {articles.category.map(category => (
               <React.Fragment key={category.id}>
                 <span>カテゴリー:{category.name}</span>
               </React.Fragment>
             ))}
        </div>
        <hr />
       </React.Fragment>
       )
     } else { return }
   })}
 </Layout>
)

export const query = graphql`
 {
    allMicrocmsArticles(
     sort: { fields: [createdAt], order: DESC }
   ) {
     edges {
       node {
         id
         title
         title_origin
         category {
           id
           name
         }
         pict {
           url
         }
         body
         feature
       }
     }
   }
 }
`

export default PatientsPage

そして
gatsby developで立ち上げてhttps://localhost:8000/patientsにアクセスする。ふたつの記事のタイトルと紹介文と紹介画像が降順で表示されている。
image.png

GraphQLというのはよくわからんがこんな書き方をするのだなあ、と。

// pages/patients.js
・・・略・・・

export const query = graphql`
 {
    allMicrocmsArticles(
     sort: { fields: [createdAt], order: DESC }
   ) {
     edges {
       node {
         id
         title
         title_origin
         category {
           id
           name
         }
         pict {
           url
         }
         body
         feature
       }
     }
   }
 }
`
・・・略・・・

http://localhost:8000/___graphqlにアクセスしてみる。するとGraphQLで受け取ってるデータとデータ構造が見れる。
image.png

allMicrocmsArticlesのedgesのnodeに記事のすべてが詰まってる。
image.png

GraphQLでうけとったデータをmapで回してじゅんぐりに表示、ということである。

個別記事の全表示ページを作成

動的なページを作成する際にはデフォではカラだったgatsby-node.jsファイルにコードする(えっ?)。そういうキマリ。

// gatsby-node.js
const path = require("path")

exports.createPages = async ({ graphql, actions }) => {
 const { createPage } = actions

 const result = await graphql(
   `
     {
        allMicrocmsArticles {
         edges {
           node {
             id
             title
             title_origin
             category {
                id
                name
             }
             body
             feature
             pict {
                 url
             }
           }
         }
       }
     }
   `
 )

 if (result.errors) {
   throw result.errors
 }

 result.data.allMicrocmsArticles.edges.forEach(edge => {
     //上記のGraphQLでcategoryを書いてないがnode.categoryを掴めるようだ
     const categoryName = edge.node.category[0].name
     switch (categoryName) {
         case 'patients':  // categoryがpatientsだったらサブパスをpatientsに
             subDir = '/patients/'+ edge.node.id
             break;
         case 'doctors':  // categoryがdoctorsだったらサブパスをdoctorsに
             subDir = '/doctors/'+edge.node.id
             break;
         default:
             subDir = '/articles/'+edge.node.id
     }
   createPage({
     //path: `/patients/${edge.node.id}`,
     path: `${subDir}`,
     component: path.resolve(
       "./src/templates/article.js"
     ),
     context: {
       id: edge.node.id,
     },
   })

 })
}

動的なページを作成するためにGatsbyにはcreatePagesというAPIが用意されてて、上のコードで肝になるのはそのcreatePages関数の中だけ。わたしは患者向け記事と医師向け記事と…でサブパスを分けたかったのでSwitch文があるが、単純に以下のようにシンプルでよい。

 result.data.allMicrocmsArticles.edges.forEach(edge => {
   createPage({
     path: `/articles/${edge.node.id}`,
     component: path.resolve(
       "./src/templates/article.js"
     ),
     context: {
       id: edge.node.id,
     },
   })

 })

component: path.resolve(
"./src/templates/article.js"
)

ではテンプレートビューファイルであるarticle.jsを指定してる。次のステップで作成する。
作成先がtemplatesフォルダになるのはそういうキマリかもしくは慣習。

context: {
id: edge.node.id,
}

では記事データのIDを指定している。こう書くだけで次のステップで作成するテンプレートに値渡しできるようである。

ではtemplatesフォルダを作成。
そしてその下にarticle.jsファイルを作成(ファイル名は任意)。

//templates/article.js
import React from "react"
import { graphql } from "gatsby"

import Layout from "../components/layout"

const ArticlePost = props => {
 const post = props.data.microcmsArticles // ㊟allMicrocmsArticleでない
 return (
   <Layout>
     <div>
       <h2>{post.title}</h2>
       <h3>原文:{post.title_origin}</h3>
       <br />
       <img
         src={post.pict.url}
         width={160}
         height={110}
         alt="pict画像"
       />
       <p
         dangerouslySetInnerHTML={{
           __html: `${post.body}`,
         }}
       ></p>
     </div>
   </Layout>
 )
}

export default ArticlePost

export const query = graphql`
 query($id: String!) {
   microcmsArticles(id: { eq: $id }) {
     title
     title_origin
     body
     pict {
       url
     }
     body
   }
 }
`

34行目のmicrocmsArticles(id: { eq: $id })で、gatsby-node.jsのcontextで指定した記事IDが値渡しされている。そしてそのIDをもとにmicrocmsArticlesからデータをGraphQLで引っ張っている。個別の記事をとってきたいのでallMicrocmsArticleではないところ、注意。



さいごにpatients.jsにリンクをはる。

// pages/patients.js
・・・略・・・
        <React.Fragment key={articles.id}>
         <div>
             <Link to={`/patients/${articles.id}`}>
                <h2>{articles.title}</h2>
             </Link>
             <p>{articles.feature}</p>
・・・略・・・

これでgatsby developでビルドしなおすと(gatsby-node.jsファイルのコードを変更すると、変更内容にもよるがビルドしなおさないといけないみたい)詳細ページが表示されるようになる。

患者向け②をクリックしてみる
image.png

表示された。
image.png

URLはコレ

http://localhost:8000/patients/a9cd9e19-8a1f-5ad9-b753-00bc8dbfa875

titleをURLにしたかったらedge.node.titleにすれば以下のようになるだろう。日本語がイヤだったら記事コンテンツAPIに英語タイトルのフィールドを追加するだけだ(半角スペースはいれないよう)
http://localhost:8000/patients/患者さん用記事②

リロードしても404エラーにならない。すばらしい。


補足

医師向け記事も同じようにしてふたつ作った。
image.png

pagesフォルダの下にdoctors.jsファイルを作成、patients.jsのコードをコピペして少し編集しただけ。microCMS側では記事を作成時、カテゴリーをdoctorsにするだけだ。
image.png

もちろん、gatsby-node.jstemplates/article.jsはなにも変更する必要ない。

// pages/doctors.js
import React from "react"
import { graphql, Link } from "gatsby"

import Layout from "../components/layout"
import SEO from "../components/seo"


const PatientsPage = ({ data }) => (
 <Layout>
   <SEO title="医師の方へ" />

   {data.allMicrocmsArticles.edges.map(edge => {
     const articles = edge.node
     const category = edge.node.category[0].name

     console.log('◆categoryは ' + category)
     console.log('◆articles.idは ' + articles.id)
     console.log('◆リンク先は ' + `/doctors/${articles.id}`)

     if (category === 'doctors') {      //カテゴリーが医師用の場合表示
       return (
        <React.Fragment key={articles.id}>
         <div>
             <Link to={`/doctors/${articles.id}`}>
                <h2>{articles.title}</h2>
             </Link>
             <p>{articles.feature}</p>
           <img
             src={articles.pict.url}
             width={110}
             height={110}
             alt="pict画像"
           />
         </div>
         <div>
         {articles.category.map(category => (
               <React.Fragment key={category.id}>
                 <span>カテゴリー:{category.name}</span>
               </React.Fragment>
         ))}
        </div>
        <hr />
       </React.Fragment>
       )
     }
   })}
 </Layout>
)

export const query = graphql`
 {
    allMicrocmsArticles(
     sort: { fields: [createdAt], order: DESC }
   ) {
     edges {
       node {
         id
         title
         title_origin
         category {
           id
           name
         }
         pict {
           url
         }
         body
         feature
       }
     }
   }
 }
`

export default PatientsPage



参考:
gatsby-source-microcms
話題のHeadlessCMS「microCMS」を試してみたwith Gatsby ~part2 Gatsbyを使ってViewを表示~
Next.js + microCMS + NetlifyでJAMstackな世界に入門する

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

新卒エンジニアに送るReact + Reduxの習熟度チェックリスト

なんとなくだけどこれくらいできるといいなーと思ったことをまとめていたらチェックリスト方式になったので公開。まだ項目として足りない部分があるけどそれは今後追加していけば良いかなと。

これ足りないよ〜とかありましたらコメントいただけますと嬉しいです。

前提

  • Create React Appでプロジェクトを開始できる
  • React公式のチュートリアルを完了している

初級者

  • Stateの更新・propsの使用ができる
  • 配列を使って要素の描画ができる
  • formを使ってpostすることができる
  • ライフサイクルメソッドを使うことができる
  • UIライブラリを使ってスタイルを付けられる

簡単なビューであれば作成・修正ができるレベル

  • lintの設定ができる
  • Formaterの設定ができる
  • react-routerを使いページ遷移をさせることができる。
  • 配列内のkeyの意味がわかる。また、keyにどんな値を入れるのが適切なのか述べることができる
  • 余計なdivタグを書かずにマークアップできる(fragmentを使う)
  • スタイルの適用ができる

基本的なビューであれば問題なく任せられるレベル

  • classコンポーネントと関数コンポーネントの違い・メリット・デメリットがわかる
  • TypeScriptを使って書くことができる
  • TypeScriptで書くことのメリットを述べることができる
  • Reduxが何をしているか理解している
  • Reduxを使ってStateの更新をすることができる
  • APIを使ってデータの取得・更新ができる。また、Storeに入れることができる。
  • hooksを使ってコードを書くことができる
  • ライフサイクルメソッドを理解して使うことができる。また、あまり使用しない方が良い理由を述べることができる

1人月として計算ができレビューも任せられるレベル

  • テストコードを書くことができる
  • メモリーリークに気をつけてコーディングできる
  • ログイン・サインアップなどAuth周りの実装ができる
  • Reduxのメリット・デメリットを述べることができる
  • middlewareで処理をすることができる。また、そのメリットデメリットを述べられる
  • ReactのComponentとは何か理解している
  • 必要であればカスタムhooksを作ることができる
  • Code-Splittingを使うことができる。また、そのメリットを述べることができる。
  • レビューすることができる

0からのプロジェクトでも難なくこなせるレベル

  • Componentの設計ができる
  • エラーハンドリングを実装できる
  • Reduxを使う基盤を設計することができる
  • パフォーマンスの改善ができる
  • そのプロジェクトでどの範囲のテストをする必要があるのか判断でき、指標を示すことができる
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む