React 動的テーブル行とセレクトボックス

動作テスト

import { useEffect, useState } from 'react';

interface TestInterface {
  id: number;
  field1: string;
  field2: string;
}

let defs = [
  {key:'-', value:'-'}, {key:'001', value:'A'},
  {key:'002', value:'B'}, {key:'003', value:'C'},
  {key:'004', value:'D'}, {key:'005', value:'E'},
  {key:'006', value:'F'}, {key:'007', value:'G'}
];

let columns = new Map();
columns.set('001', ['dataA-1', 'dataA-2', 'dataA-3']);
columns.set('002', ['dataB-1', 'dataB-2', 'dataB-3']);
columns.set('003', ['dataC-1', 'dataC-2', 'dataC-3']);
columns.set('004', ['dataD-1', 'dataD-2', 'dataD-3']);
columns.set('005', ['dataE-1', 'dataE-2', 'dataE-3']);
columns.set('006', ['dataF-1', 'dataF-2', 'dataF-3']);
columns.set('007', ['dataG-1', 'dataG-2', 'dataG-3']);

const CustomTable = () => {
  const [users, setUsers] = useState<TestInterface[]>([]);
  const[count, setCount] = useState<number>(1);

  useEffect(() => {
  }, [users]);

  const addRow = () => {
    const user : TestInterface = { id: count,  field1: '-', field2: '-' };
    setCount(count+1);
    setUsers([...users, user]);
  }

  const deleteRow = (i : number) => {
    setUsers(users.filter((user) => (user.id !== i)));
  }

  const upRow = (id: number, index:number) => {
    if (index === 0 || users.length < 2) {
      return;
    }
    for (let j = 1; j < users.length; j++) {
      const user2 : TestInterface = users[j];
      if (user2.id === id) {
        setUsers((prevState) => {
          // オブジェクトをコピーしないと再描画されない。
          let tempUsers : TestInterface[] = [...prevState];
          const moving = tempUsers.splice(j, 1)[0];
          tempUsers.splice(j - 1, 0, moving);
          return tempUsers;
        });
        break;
      }
    }
  }

  const downRow = (id: number, index:number) => {
    if (index === users.length -1 || users.length < 2) {
      return;
    }
    for (let j = 0; j < users.length-1; j++) {
      const user2 : TestInterface = users[j];
      if (user2.id === id) {
        setUsers((prevState) => {
          // オブジェクトをコピーしないと再描画されない。
          let tempUsers : TestInterface[] = [...prevState];
          const moving = tempUsers.splice(j, 1)[0];
          tempUsers.splice(j + 1, 0, moving);
          return tempUsers;
        });
        break;
      }
    }
  }

  const onChange1 = (id: number, e: any) => {
    setUsers((prevState) => {
      // オブジェクトをコピーしないと再描画されない。
      let tempUsers : TestInterface[] = [...prevState];
      let test1: TestInterface = tempUsers.filter((elem) => elem.id === id)[0];
      test1.field1 = e.target.value;
      return tempUsers;
    });
  }

  const onChange2 = (id: number, e: any) => {
    setUsers((prevState) => {
      // オブジェクトをコピーしないと再描画されない。
      let tempUsers : TestInterface[] = [...prevState];
      let test1: TestInterface = tempUsers.filter((elem) => elem.id === id)[0];
      test1.field2 = e.target.value;
      return tempUsers;
    });
  }

  const Field2 = (props: any) => {
    if (props.user.field1 === '-') {
      return (
        <select name="field2" onChange={(e) => onChange2(props.user.id, e)} value={props.user.field2}>
          <option value="-">-</option>
        </select>
      );
    }
    else {
      const options: string[] = columns.get(props.user.field1);
      return (
        <select name="field2" onChange={(e) => onChange2(props.user.id, e)} value={props.user.field2}>
          {options.map((value: string, index: number) => (
            <option value={value} key={index}>{value}</option>
          ))}
        </select>
      );
    }
  }

  const setData = (e: any) => {
    if (e.target.value === '1') {
      const _users : TestInterface[] = [
        { id: 1,  field1: '001', field2: 'dataA-1' },
        { id: 2,  field1: '-', field2: '-' },
        { id: 3,  field1: '002', field2: 'dataB-1' },
      ];
      setCount(_users.length + 1);
      setUsers(_users);
    }
    else if (e.target.value === '2') {
      const _users : TestInterface[] = [
        { id: 1,  field1: '003', field2: 'dataC-1' },
        { id: 2,  field1: '-', field2: '-' },
        { id: 3,  field1: '004', field2: 'dataD-1' },
        { id: 4,  field1: '005', field2: 'dataE-3' },
      ];
      setCount(_users.length + 1);
      setUsers(_users);
    }
    else if (e.target.value === '3') {
      const _users : TestInterface[] = [
        { id: 1,  field1: '003', field2: 'dataC-1' },
        { id: 2,  field1: '-', field2: '-' },
        { id: 3,  field1: '004', field2: 'dataD-1' },
        { id: 4,  field1: '004', field2: 'dataD-2' },
        { id: 5,  field1: '005', field2: 'dataE-3' },
      ];
      setCount(_users.length + 1);
      setUsers(_users);
    }
  }

  return (
    <div>
      データのロード
      <select onClick={(e) => setData(e)}>
        <option value="-">-</option>
        <option value="1">1</option>
        <option value="2">2</option>
        <option value="3">3</option>
      </select>
      <table>
        <thead>
          <tr>
            <th>ID</th>
            <th>フィールド1</th>
            <th>フィールド2</th>
            <th></th>
          </tr>
        </thead>
        <tbody>
          {users.map((user: TestInterface, index: number) => (
            <tr
                key={user.id}
            >
              <td>{user.id}</td>
              <td>
                <select name="field1" onChange={(e) => onChange1(user.id, e)} value={user.field1}>
                  {defs.map((item: any, index: number) => (
                    <option value={item.key} key={index}>{item.value}</option>
                  ))}
                </select>
              </td>
              <td>
                <Field2 user={user} />
              </td>
              <td>
                <button onClick={() => upRow(user.id, index)}>上へ</button>
                <button onClick={() => downRow(user.id, index)}>下へ</button>
                <button onClick={() => deleteRow(user.id)}>削除</button>
              </td>
            </tr>
          ))}
        </tbody>
      </table>
      <button onClick={() => addRow()}>追加</button>
    </div>
  );
};

export default CustomTable;

 

投稿日: