Open22

React,Next.jsの覚え書き(設計手法なども含む)

aibizaibiz

コンポーネント名はパスカルケース(先頭は大文字)にする
〇:Text、Message
×:text、message

aibizaibiz

Next.jsの4つのレンダリング手法

  • 静的サイト生成(SSG:Static Site Generation)
    • getStaticProps、getStaticPaths
  • クライアントサイドレンダリング(CSR:Client Side Rendering)
  • サーバーサイドレンダリング(SSR:Server Side Rendering)
    • getServerSideProps
  • インクリメンタル静的再生性(ISR:Incremental Static Regeneration)
aibizaibiz

Next.jsでstyled-componentsをインストール

npm install styled-components@latest
npm install --save-dev @types/styled-components

注意

npm install styled-components

だとエラー
npm ERR! Cannot read properties of null (reading 'edgesOut')

aibizaibiz

ESLint(リントツール)とPrettier(フォーマッター)関連のライブラリ

  • eslint
  • prettier
  • typescript-eslint
  • @typescript-eslint/eslint-plugin
  • @typescript-eslint/parser
  • eslint-plugin-prettier
  • eslint-plugin-react
  • eslint-plugin-react-hooks
  • eslint-plugin-import
aibizaibiz

storybook関連のライブラリ

  • @storybook/addon-postcss
  • tsconfig-paths-webpack-plugin
  • @babel/ plugin-proposal-class-properties
  • @babel/ plugin-proposal-private-methods
  • @babel/ plugin-proposal-private-property-in-object
  • tsconfig-paths-webpack-plugin
  • @mdx-js/react
aibizaibiz

マテリアルUI系のインストール
@mui/material
@mui/icons-material
@emotion/react
@emotion/styled

aibizaibiz

テスト環境構築
npm install --save-dev @testing-library/jest-dom @testing-library/react jest jest-environment-jsdom

aibizaibiz

コンポーネント設計

Presentational Component プレゼンテーショナル コンポーネント

見た目、デザインを実装するコンポーネント

//import './styles.css'

type ButtonProps = { 
  label: string 
  text: string 
  disabled: boolean 
  onClick: React.MouseEventHandler<HTMLButtonElement>
}

//ラベルとボタンを表示するコンポーネント
export const Button = (props: ButtonProps) => {
  const { label, text, disabled, onClick } = props

  //propsで渡されたデータを元に見た目を実装する
  return (
    <div className =" button-container">
      <span>{ label }</span>
      <button disabled={ disabled } onClick={ onClick }>
        { text } 
      </button>
    </div>
  )
}

export default Button

Container Component コンテナ コンポーネント

ビジネスロジックのみを実装するコンポーネント

import { useState, useCallback } from 'react'
import { Button } from './presentational-sample'

//ポップアップを表示するためのフック
const usePopup = () => { 
  //与えられたテキストを表示するポップアップを出現させる関数
  const cb = useCallback(( text: string) => {
    prompt( text )
  }, [])
  
  return cb
}

type CountButtonProps = { 
  label: string
  maximum: number
} 

//クリックされた回数を表示するボタンを表示するコンポーネント
export const CountButton = (props: CountButtonProps) => {
  const { label, maximum } = props
  
  //アラートを表示させるためのフックを使う
  const displayPopup = usePopup() 
  
  //カウントを保持する状態を定義する
  const [count, setCount] = useState(0) 
  
  //ボタンが押された時の挙動を定義する
  const onClick = useCallback(() => { 
  //カウントを更新する
  const newCount = count + 1
  setCount(newCount)

  if (newCount >= maximum) {
    // アラートを出す
    displayPopup(`You've clicked ${ newCount} times `)
  }
}, [count, maximum])
//状態を元に表示に必要なデータを求める
const disabled = count >= maximum
const text = disabled 
  ? 'Can\' t click any more'
  : `You've clicked ${ count} times`
  // Presentational Componentを返す
  return (
    <Button disabled={ disabled } onClick={ onClick } label ={ label } text ={text } />
  )
}

export default CountButton
aibizaibiz

Atomic Design アトミックデザイン

Atoms

最小の要素。これ以上分割できない
例)ボタン、テキスト

Molecules

複数のAtomsを組み合わせて構築
例)ラベル付きのテキストボックス

Organisms

Moleculesよりも具体的な要素
例)入力フォーム

Templates

ページ全体のレイアウト
例)ページのレイアウト

Pages

ページそのもの
例)ページそのもの

aibizaibiz

サーバーコンポーネントとクライアントコンポーネントについて

https://nextjs.org/docs/getting-started/react-essentials

サーバー コンポーネントとクライアント コンポーネントの決定を簡素化するために、クライアント コンポーネントの使用例が決まるまではサーバー コンポーネント (appディレクトリ内のデフォルト) を使用することをお勧めします。

https://nextjs.org/docs/getting-started/react-essentials

「クライアントを使用する」ディレクティブ

指令"use client"_は、サーバー コンポーネント モジュール グラフとクライアント コンポーネント モジュール グラフの間の境界を宣言するための規則です。

https://nextjs.org/docs/getting-started/react-essentials#the-use-client-directive

aibizaibiz

テクニック 即時関数の中でif文を実行する

        <div>
        {
          //即時関数の中でif文を実行する
          (()=> {
            if( currentPos === 'main' ) {
              return (<Main />) 
            } else if( currentPos === 'fontsize' ) {
              return (<Fontsize />)
            } else {
              return ("コンポーネントがない!")
            }
          })()
        }
        </div>