75654


ユーザー側で項目を増減できるテキストフォーム入りリストを作成しています。  
下記はデモです。  
Reactを使用しています。  
[CodeSandBox](https://codesandbox.io/embed/elastic-austin-
nxpku?fontsize=14&hidenavigation=1&theme=dark)  
リスト直下の`Add item`を押すことで、リスト追加できます。  
リストの右端の`×`を押すことで、リストを削除できます。

現状リストの増減はできるようになったのですが、テキストフォームに値を入力した状態で入力したリストを削除すると、リストは削除できるものの、フォームの値が削除されない状態です。  
[![gif](https://i.stack.imgur.com/cHMK4.gif)](https://i.stack.imgur.com/cHMK4.gif)

リストの左端`Number`の値は識別子ではなくリストの数を表現したいので`Number`の値は変わらなくてよいのですが、フォームの値は削除したいです。

* * *

下記がコードです。

[code]

    export default function App() {
    　const defaultItem = { a: "", b: "", c: "" };
      const [items, setItems] = useState([defaultItem]);
      const [length, setLength] = useState(1);
    
      const addItem = () => {
        if (length > 4) return;
        setItems((items) => [...items, defaultItem]);
        setLength((length) => length + 1);
      };
      const deleteItem = ({ target: { name } }) => {
        const newItemArray = [...items];
        newItemArray.splice(Number(name), 1);
        setItems(newItemArray);
        setLength((length) => length - 1);
      };
    
      const itemList = items.map((item, index) => {
        return (
          <tr key={index}>
            <td>{index + 1}</td>
            <td>
              <input type="text" name="a" defaultValue={item.a} />
            </td>
            <td>
              <input type="text" name="a" defaultValue={item.b} />
            </td>
            <td>
              <input type="text" name="a" defaultValue={item.c} />
            </td>
            <td>
              <button onClick={deleteItem} name={index.toString()}>
                ×
              </button>
            </td>
          </tr>
        );
      });
    
      const submitList = (e) => {
        e.preventDefault();
      };
    
      return (
        <form onSubmit={submitList}>
          <table>
            <thead>
              <tr>
                <th>Number</th>
                <th>A</th>
                <th>B</th>
                <th>C</th>
                <th>Delete</th>
              </tr>
            </thead>
            <tbody>{itemList}</tbody>
          </table>
          <button onClick={addItem} disabled={length > 4 ? true : false}>
            Add item
          </button>
          <hr />
          <input type="submit" value="Submit" />
        </form>
      );
    }
    
[/code]

リストの削除は下記の関数です。

[code]

    const deleteItem = ({ target: { name } }) => {
      const newItemArray = [...items];
      newItemArray.splice(Number(name), 1);
      setItems(newItemArray);
      setLength((length) => length - 1);
    };
    
[/code]

リスト削除ボタンの`name`属性にリストの`index`番号を設定して、削除ボタン押下時に`name`属性からリストの番号を取得し、該当する番号のリストを削除する、という処理を狙っています。


CC BY-SA 4.0
2021-05-03T08:49:47.043
75650
2021-05-03T16:31:03.130
35433
question
javascript reactjs
input要素を含んだ配列を削除する際、削除するinputのvalueも削除したい


リストと key – React  
<https://ja.reactjs.org/docs/lists-and-keys.html#keys>

> 要素の並び順が変更される可能性がある場合、インデックスを key
> として使用することはお勧めしません。パフォーマンスに悪い影響を与え、コンポーネントの状態に問題を起こす可能性があります。Robin Pokorny
> による、[key としてインデックスを用いる際の悪影響](https://medium.com/@robinpokorny/index-as-a-
> key-is-an-anti-pattern-e0349aece318)についての詳しい解説をご覧ください。より詳しく学びたい場合は、[key
> が何故必要なのかについての詳しい解説](https://ja.reactjs.org/docs/reconciliation.html#recursing-
> on-children)を参照してください。

Index as a key is an anti-pattern (React) | by Robin Pokorny | Medium  
<https://robinpokorny.medium.com/index-as-a-key-is-an-anti-
pattern-e0349aece318>

> Many people asked if they always, _always_ have to generate ids. Others have
> suggested use cases when using the index as a key seems justifiable.
>
> It is true that sometimes generating new ids is redundant and may be
> avoided. For example translation of license terms or list of contributors.
>
> To help you decide, I put together three conditions which these examples
> have in common:
>
>   1. the list and items are static–they are not computed and do not change;
>   2. the items in the list have no ids;
>   3. the list is never reordered or filtered.
>

* * *

今回のコード例のリストは `the list and items are static–they are not computed and do not
change` ではないので、 `item` それぞれに固有の識別子が必要です。

実際のアプリケーションコードでそれぞれの `item` に使用できそうな識別子があれば、それを利用してください。

実際のコードでも識別子がない場合、[nanoid](https://github.com/ai/nanoid/)などのライブラリを使って識別子の生成を検討してください。

以下のコードは識別子に `new Date().getTime()` を使用した例になります。  
(回答の為のサンプルコードとして使用しています。私が `new Date().getTime()` の使用を **推奨しているわけではない**
ことに注意してください)

[code]

    function App() {
      const defaultItem = () => ({ id: new Date().getTime(), a: "", b: "", c: "" });
      const [items, setItems] = React.useState([defaultItem()]);
      const [length, setLength] = React.useState(1);
    
      const addItem = () => {
        if (length > 4) return;
        setItems((items) => [...items, defaultItem()]);
        setLength((length) => length + 1);
      };
      const deleteItem = ({ target: { name } }) => {
        const newItemArray = [...items];
        newItemArray.splice(Number(name), 1);
        setItems(newItemArray);
        setLength((length) => length - 1);
      };
    
      const itemList = items.map((item, index) => {
        return (
          <tr key={item.id}>
            <td>{index + 1}</td>
            <td>
              <input type="text" name="a" defaultValue={item.a} />
            </td>
            <td>
              <input type="text" name="a" defaultValue={item.b} />
            </td>
            <td>
              <input type="text" name="a" defaultValue={item.c} />
            </td>
            <td>
              <button onClick={deleteItem} name={index.toString()}>
                ×
              </button>
            </td>
          </tr>
        );
      });
    
      const submitList = (e) => {
        e.preventDefault();
      };
    
      return (
        <form onSubmit={submitList}>
          <table>
            <thead>
              <tr>
                <th>Number</th>
                <th>A</th>
                <th>B</th>
                <th>C</th>
                <th>Delete</th>
              </tr>
            </thead>
            <tbody>{itemList}</tbody>
          </table>
          <button onClick={addItem} disabled={length > 4 ? true : false}>
            Add item
          </button>
          <hr />
          <input type="submit" value="Submit" />
        </form>
      );
    }
    
    ReactDOM.render(
      <React.StrictMode>
        <App />
      </React.StrictMode>,
      document.getElementById("root")
    );
[/code]

[code]

    <script crossorigin src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
    
    <div id="root"></div>
[/code]


CC BY-SA 4.0
2021-05-03T10:42:15.827
75654
2021-05-03T16:31:03.130
2021-05-03T16:31:03.130
3068
3068
75650
answer