技術系

ゴミコードからの軌跡 ~Trash Revision~

技術系

こんにちは!
ゴミコード生産機こと、なかにしです。

現在は実務でReactを書いているのですが、ゴミコードを量産しています。

さすがにヤバいと思い、最近は睡眠時間を削って勉強してます。

そのおかげでちょっとましになってきたので、
これまでに書いてきたゴミコードを供養しようと思います!

これから実務だけど不安…という方も、
こんなゴミコードでもOKなんだーと安心していただけたらと思います!

それではいってみよう!

メンバー紹介

全部紹介しているときりがないので、今回は一番ヤバかった「テーブル」のコードを紹介します!

▽まずは完成品がこちら

あれ?割と普通じゃね?
そうです。見た目は問題ないんです。

▽コードはこちらです!!!

import React, { CSSProperties } from 'react'
export default function  Table(){

  // ボーダーの設定
  const border = 1;
  
  // テーブルのスタイル
  const tableStyle:CSSProperties = {
    borderCollapse: "collapse",
  }

  // テーブル結合
  const colSpan = 3; 

  // 行のスタイル
  const rowStyle = {
    minWidth: '150px',
  }

  // 削除ボタンのスタイル
  const deleteButtonStyle = {
    padding: "10px",
    margin: "5px 10px",
    backgroundColor: '#f88d7a',
  }

  // 追加ボタンのスタイル
  const addButtonStyle = {
    padding: "10px",
    margin: "5px 10px",
    backgroundColor: '#a8e1f8',
  }

  // 入力テキストボックスのスタイル
  const textBoxStyle = {
    margin: '10px',
  }

   // 「↑」ボタンを押した時の挙動
  const upRow = () => {
      省略
  }

  // 「↓」ボタンを押した時の挙動
  const downRow = () => {
      省略
  }

  // 削除ボタンを押したときの挙動
  const deleteRow = () => {
      省略
  }

  // 追加ボタンを押したときの挙動
  const createRow = () => {
      省略
  }

  return (
  <div>
    <table border={ border } style={ tableStyle }>
      <thead>
        <tr>
          <th style={ rowStyle }>ID</th>
          <th style={ rowStyle }>Name</th>
          <th style={ rowStyle }>Age</th>
          <th colSpan={ colSpan } style={ rowStyle }>操作</th>
        </tr>
      </thead>
      <tbody>

        <tr>
          <td>1</td>
          <td>Tanaka</td>
          <td>12</td>
          <td><button onClick={ () => deleteRow() } style={ deleteButtonStyle } >削除</button></td>
          <td><button onClick={ () => upRow() }>↑</button></td>
          <td><button onClick={ () => downRow() }>↓</button></td>
        </tr>
        
        <tr>
          <td>2</td>
          <td>Nakanishi</td>
          <td>24</td>
          <td><button onClick={ () => deleteRow() } style={ deleteButtonStyle } >削除</button></td>
          <td><button onClick={ () => upRow() }>↑</button></td>
          <td><button onClick={ () => downRow() }>↓</button></td>
        </tr>

        <tr>
          <td>3</td>
          <td>Akiyama</td>
          <td>45</td>
          <td><button onClick={ () => deleteRow() } style={ deleteButtonStyle } >削除</button></td>
          <td><button onClick={ () => upRow() }>↑</button></td>
          <td><button onClick={ () => downRow() }>↓</button></td>
        </tr>

        <tr>
          <td>4</td>
          <td>Takayama</td>
          <td>22</td>
          <td><button onClick={ () => deleteRow() } style={ deleteButtonStyle } >削除</button></td>
          <td><button onClick={ () => upRow() }>↑</button></td>
          <td><button onClick={ () => downRow() }>↓</button></td>
        </tr>

        <tr>
          <td>5</td>
          <td>Nishi</td>
          <td>8</td>
          <td><button onClick={ () => deleteRow() } style={ deleteButtonStyle } >削除</button></td>
          <td><button onClick={ () => upRow() }>↑</button></td>
          <td><button onClick={ () => downRow() }>↓</button></td>
        </tr>

        <tr>
          <td><input type='text' placeholder='IDを入力' style={ textBoxStyle } /></td>
          <td><input type='text' placeholder='名前を入力' style={ textBoxStyle } /></td>
          <td><input type='text' placeholder='年齢を入力' style={ textBoxStyle } /></td>
          <td><button onClick={ () => createRow() } style={ addButtonStyle } >追加</button></td>
          <td><button onClick={ () => upRow() }></button></td>
          <td><button onClick={ () => downRow() }></button></td>
        </tr>

      </tbody>
    </table>
  </div>
  )
}

Reactって知ってる?

すみません…よく分かってなかったです…

React × TypeScriptは初心者すぎて、
試行錯誤するよりHTMLとCSSとJSでごり押した方が早い!!
って思っちゃうんですよね…反省してます。

てか長い。全体的に。
ダミーデータ入れるの1つずつ手作業なのも頭悪い。

今の職場は割と動けばいいスタイルなのでなんとかなってますが、
コードに厳しい案件だったら即切りですね。こんなの。

修正後

CSSはSCSSファイル、ダミーデータはJSONファイルに切り分けました。
ダミーデータはmap関数で配列処理をして、量が多くなっても安心!

[
  {"id": 1, "name": "Tanaka", "age": 12},
  {"id": 2, "name": "Nakanishi", "age": 24},
  {"id": 3, "name": "Akiyama", "age": 45},
  {"id": 4, "name": "Takayama", "age": 22},
  {"id": 5, "name": "Nishi", "age": 8}
]
.tableStyle{
  border-collapse: collapse;
}

.rowStyle{
  width: 150px;
}

.deleteButtonStyle{
  padding: 10px;
  margin: 5px 10px;
  background-color: #f88d7a;
}

.createButtonStyle{
  padding: 10px;
  margin: 5px 10px;
  background-color: #a8e1f8;
}

.textBoxStyle{
  margin: 10px,
}
import React from 'react'
import classes from './Table.module.scss';
import data from './Data.json';

export default function  Table(){

  // ボーダーの設定
  const border:number = 1;

  // テーブル結合
  const colSpan:number = 3; 

  // 「↑」ボタンを押した時の挙動
  const upRow = () => {
     省略
  }

  // 「↓」ボタンを押した時の挙動
  const downRow = () => {
     省略
  }

  // 削除ボタンを押したときの挙動
  const deleteRow = () => {
     省略
  }

  // 追加ボタンを押したときの挙動
  const createRow = () => {
     省略
  }

  // Jsonの型一覧を定義
  interface elm {
    id: number,
    name: string,
    age: number,
  }

  return (
  <div>
    <table border={ border } className={ classes.tableStyle }>
      <thead>
        <tr>
          <th className={ classes.rowStyle }>ID</th>
          <th className={ classes.rowStyle }>Name</th>
          <th className={ classes.rowStyle }>Age</th>
          <th colSpan={ colSpan } className={ classes.rowStyle }>操作</th>
        </tr>
      </thead>
      <tbody>
        { data.map((elm:elm, index:number) => 
          <tr key={index}>
            <td>{ elm.id }</td>
            <td>{ elm.name }</td>
            <td>{ elm.age }</td>
            <td><button onClick={ () => deleteRow() } className={ classes.deleteButtonStyle } >削除</button></td>
            <td><button onClick={ () => upRow() }>↑</button></td>
            <td><button onClick={ () => downRow() }>↓</button></td>
            </tr>) 
        }
        <tr>
            <td><input type='text' className={ classes.textBoxStyle } id='id' placeholder='IDを入力' /></td>
            <td><input type='text' className={ classes.textBoxStyle } id='name' placeholder='名前を入力' /></td>
            <td><input type='text' className={ classes.textBoxStyle } id='age' placeholder='年齢を入力' /></td>
            <td><button onClick={ () => createRow() } className={ classes.createButtonStyle } >追加</button></td>
            <td><button onClick={ () => upRow() }>↑</button></td>
            <td><button onClick={ () => downRow() }>↓</button></td>
            </tr>
      </tbody>
    </table>
  </div>
  )
}

だいぶすっきりしました 🙂
それぞれの役割に切り分けたので、拡張性も高めになってるかと思います。

一応最後まで作ります

ボタンに機能が与えられていないので、ちゃんと動くところまで作ります。
基本的にはJSON配列を基にして、useStateで追加や削除を行います。

追加ボタン:inputから値を取り出す→オブジェクトに変換→JSONに追加
削除ボタン:押したボタンのindexを取得→JSONから該当のindexのオブジェクトを削除

▽<React.StrictMode>があると仕様上
削除などが2回行われてしまうので、いったん外しておきましょう。

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import './index.css'

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
  <React.StrictMode>  // 削除
    <App />
  </React.StrictMode> // 削除
)

▽完成形です。
型がanyばっかなのは許してください…実務ではちゃんと直します…

import React, { useState } from 'react'
import classes from './Table.module.scss';
import data from './Data.json';

export default function  Table(){

  // ボーダーの設定
  const border:number = 1;

  // テーブル結合
  const colSpan:number = 3; 

  // JSONをdataに代入、初期値とする。
  // 追加や削除したものをsetTableDataして再レンダリングしていく。
  const [tableData, setTableData] = useState(data);

  // 「↑」ボタンを押した時の挙動
  const upRow = (index:number) => {
    if(index === 0){
      return;
    }

    const newData:any = [...tableData];
    [newData[index-1],newData[index]] = [newData[index],newData[index-1]];
    setTableData(newData);
  }

  // 「↓」ボタンを押した時の挙動
  const downRow = (index:number) => {
    if(index >= tableData.length-1 ){
      return;
    }

    const newData:any = [...tableData];
    [newData[index+1],newData[index]] = [newData[index],newData[index+1]];
    setTableData(newData);
  }

  // 削除ボタンを押したときの挙動
  const deleteRow = (index:number) => {
    const data = [...tableData];
    data.splice(index, 1);
    setTableData(data);
  }

  // 追加ボタンを押したときの挙動
  const createRow = () => {
    const idData:any = document.getElementById('id');
    const nameData:any = document.getElementById('name');
    const ageData:any = document.getElementById('age');

    if(idData.value && nameData.value && ageData.value){
      if(!isNaN(Number(idData.value)) && !isNaN(Number(ageData.value))){
        
        const newData:any = {id: Number(idData.value), name: nameData.value, age: Number(ageData.value) }
        const data = [...tableData];
        data.push(newData);
        setTableData(data);
      }
    }
  }

  // Jsonの型一覧を定義
  interface elm {
    id: number,
    name: string,
    age: number,
  }

  return (
  <div>
    <table border={ border } className={ classes.tableStyle }>
      <thead>
        <tr>
          <th className={ classes.rowStyle }>ID</th>
          <th className={ classes.rowStyle }>Name</th>
          <th className={ classes.rowStyle }>Age</th>
          <th colSpan={ colSpan } className={ classes.rowStyle }>操作</th>
        </tr>
      </thead>
      <tbody>
        { tableData.map((elm:elm, index:number) => 
          <tr key={index}>
            <td>{ elm.id }</td>
            <td>{ elm.name }</td>
            <td>{ elm.age }</td>
            <td><button onClick={ () => deleteRow(index) } className={ classes.deleteButtonStyle } >削除</button></td>
            <td><button onClick={ () => upRow(index) }>↑</button></td>
            <td><button onClick={ () => downRow(index) }>↓</button></td>
            </tr>) 
        }

        <tr>
            <td><input type='text' className={ classes.textBoxStyle } id='id' placeholder='IDを入力' /></td>
            <td><input type='text' className={ classes.textBoxStyle } id='name' placeholder='名前を入力' /></td>
            <td><input type='text' className={ classes.textBoxStyle } id='age' placeholder='年齢を入力' /></td>
            <td><button onClick={ () => createRow() } className={ classes.addButtonStyle } >追加</button></td>
            <td></td>
            <td></td>
            </tr>
      </tbody>
    </table>
  </div>
  )
}

▽動作確認(削除)

▽動作確認(上下移動)

▽動作確認(追加)

2022/10/22 追記

最近知ったのですが、Sassだと「th」や「li」など、「.」が付かない形で指定すれば、それぞれの要素にclassNameをつけずともSassファイルを読み込むだけで勝手にスタイルが反映されるみたいですね。

次から書くときはそうしよーっと。

さいごに

実務だと期日が決まっているので、
いかに早く引き出しを開けられるかが重要になってきますね~

今回のテーブルも最初は作るのに4時間~5時間くらいかかってましたが、
今なら1時間を切れると思います。

積み重ねの重要さを痛感するいい機会でした :–)
経験年数を高い人を採用したくなる気持ちもめっちゃ分かります。

今回はここまで!
Enjoy Hacking!!