Derzeit habe ich es mit einem einfachen Javascript-Array implementiert. Aber es scheint nur wenige Probleme zu geben.

  1. onChange, onDelete muss das gesamte Array durchlaufen, was besser sein könnte als O (1)
  2. Wenn ein Element gelöscht wird, werden die Schlüsseleigenschaften anderer Elemente geändert. Ich bin mir nicht sicher, ob es schlecht ist oder nicht.

Die Verwendung von immutable.js kann Problem 1 beseitigen. Ist Nummer 2 wirklich ein Problem? Gibt es eine bessere Alternative als immutable.js? Vielleicht stelle ich nicht die richtigen Fragen, was ist der beste Weg?

import React, { useState } from "react";

export default function() {
    const [rows, setRows] = useState([""]);

    const onChange = (e, i) => {
        setRows(rows.map((row, index) => (index !== i ? row : e.target.value)));
    };

    const onDelete = i => {
        setRows(rows.filter((_, index) => i !== index));
    };

    return (
        <>
            {rows.map((row, index) => {
                return (
                    <div key={index}>
                        <input value={row} onChange={e => onChange(e, index)} />
                        {index !== 0 && (
                            <button onClick={() => onDelete(index)}>
                                - delete row
                            </button>
                        )}
                    </div>
                );
            })}

            <button onClick={() => setRows(rows.concat([""]))}>
                + add row
            </button>
        </>
    );
}

UPDATE

Ich habe versucht, immutable-js OrderedMap zu verwenden. Jetzt ändert sich die Eigenschaft key von Elementen nicht und onChange und onDelete durchlaufen nicht alles. Ist das besser als zuvor?

import React, { useState } from "react";
import { OrderedMap } from "immutable";

export default function() {
    const [inputState, setInputState] = useState({
        rows: OrderedMap(),
        nextKey: Number.MIN_VALUE,
    });

    function onChange(k, v) {
        setInputState({
            ...inputState,
            rows: inputState.rows.update(k, () => v),
        });
    }

    function addRow() {
        const { rows, nextKey } = inputState;
        setInputState({
            rows: rows.set(nextKey, ""),
            nextKey: nextKey + 1,
        });
    }

    function deleteItem(k) {
        setInputState({
            ...inputState,
            rows: inputState.rows.delete(k),
        });
    }

    return (
        <>
            {inputState.rows.entrySeq().map(([k, v]) => {
                return (
                    <div key={k}>
                        <input
                            value={v}
                            onChange={({ target: { value } }) => {
                                onChange(k, value);
                            }}
                        />
                        <button onClick={() => deleteItem(k)}>-</button>
                    </div>
                );
            })}
            <button onClick={addRow}>+ add row</button>
        </>
    );
}

UPDATE: 2 Es wurde auch versucht, einfaches Javascript Map zu verwenden.

import React, { useState } from "react";

export default function() {
    const [inputState, setInputState] = useState({
        rows: new Map(),
        nextKey: Number.MIN_VALUE,
    });

    function onChange(k, v) {
        const { rows, nextKey } = inputState;
        rows.set(k, v);
        setInputState({
            nextKey,
            rows,
        });
    }

    function addRow() {
        const { rows, nextKey } = inputState;
        rows.set(nextKey, "");
        setInputState({
            rows,
            nextKey: nextKey + 1,
        });
    }

    function deleteItem(k) {
        const { rows, nextKey } = inputState;
        rows.delete(k);
        setInputState({
            nextKey,
            rows,
        });
    }

    const uiList = [];

    for (const [k, v] of inputState.rows.entries()) {
        uiList.push(
            <div key={k}>
                <input
                    value={v}
                    onChange={({ target: { value } }) => {
                        onChange(k, value);
                    }}
                />
                <button onClick={() => deleteItem(k)}>-</button>
            </div>
        );
    }

    return (
        <>
            {uiList}
            <button onClick={addRow}>+ add row</button>
        </>
    );
}

UPDATE 3 Verwenden eines einfachen Arrays, jedoch mit Schlüsseleigenschaft.

import React, { useState } from "react";

export default function() {
    const [inputState, setInputState] = useState({
        rows: [],
        nextKey: Number.MIN_VALUE,
    });

    function onChange(i, v) {
        const { rows, nextKey } = inputState;
        rows[i].value = v;
        setInputState({
            nextKey,
            rows,
        });
    }

    function addRow() {
        const { rows, nextKey } = inputState;
        rows.push({ key: nextKey, value: "" });
        setInputState({
            rows,
            nextKey: nextKey + 1,
        });
    }

    function deleteItem(i) {
        const { rows, nextKey } = inputState;
        rows.splice(i, 1);
        setInputState({
            nextKey,
            rows,
        });
    }

    return (
        <>
            {inputState.rows.map(({ key, value }, index) => {
                return (
                    <div key={key}>
                        <input
                            value={value}
                            onChange={({ target: { value } }) => {
                                onChange(index, value);
                            }}
                        />
                        <button onClick={() => deleteItem(index)}>-</button>
                    </div>
                );
            })}
            <button onClick={addRow}>+ add row</button>
        </>
    );
}
0
Dulguun Otgon 18 Feb. 2020 im 09:20

3 Antworten

Beste Antwort

Bisher sind die besten Entscheidungen

  1. Generieren Sie einen Schlüssel, der als Schlüssel verwendet werden soll.
  2. Verwenden Sie die Karte, um effizient zu aktualisieren und zu löschen.
  3. Mutiere den Staat nicht.

Die immutable Bibliothek passt perfekt zu Punkt 2 und 3. Da es ohne Mutation effizient aktualisiert und gelöscht werden kann, scheint es eine gute Wahl zu sein.

import React, { useState, useEffect } from "react";
import { OrderedMap } from "immutable";

function UsingImmutableJS({ onChange }) {
    const [inputState, setInputState] = useState({
        rows: OrderedMap(),
        nextKey: 0,
    });

    useEffect(() => {
        if (onChange) onChange([...inputState.rows.values()]);
    }, [inputState, onChange]);

    function onInputChange(k, v) {
        setInputState(prev => ({
            ...prev,
            rows: prev.rows.update(k, () => v),
        }));
    }

    function addRow() {
        setInputState(prev => ({
            nextKey: prev.nextKey + 1,
            rows: prev.rows.set(prev.nextKey, ""),
        }));
    }

    function deleteItem(k) {
        setInputState(prev => ({
            ...prev,
            rows: prev.rows.delete(k),
        }));
    }

    return (
        <>
            {inputState.rows.entrySeq().map(([k, v]) => {
                return (
                    <div key={k}>
                        <input
                            value={v}
                            onChange={({ target: { value } }) => {
                                onInputChange(k, value);
                            }}
                        />
                        <button onClick={() => deleteItem(k)}>-</button>
                    </div>
                );
            })}
            <button onClick={addRow}>+ add row</button>
            <button onClick={() => console.log([...inputState.rows.values()])}>
                print
            </button>
        </>
    );
}
0
Dulguun Otgon 18 Feb. 2020 im 11:32

Anstatt externe js zu verwenden, mache ich nur die kleine Änderung des Codes, anstatt die Karte oder den Filter zu machen, können Sie direkt mit Spleiß verwenden,

Der folgende Code hilft dabei, das Löschen schnell durchzuführen, und behält auch nach dem Löschen den gleichen Index bei.

import React, { useState } from "react";

export default function() {
    const [rows, setRows] = useState([""]);

    const onChange = (e, i) => {
      const {value} = e.target;
      setRows(prev => {
          prev[i] = value;
          return [...prev];
        });
    };

    const onDelete = i => {
        setRows(prev => {
          prev.splice(i,1, undefined);
          return [...prev];
        });
    };
    return (
        <>
            {rows.map((row, index) => (typeof row !== "undefined") && (
              <div key={index}>
                        <input value={row} onChange={e => onChange(e, index)} />
                        {index !== 0 && (
                            <button onClick={() => onDelete(index)}>
                                - delete row
                            </button>
                        )}
                    </div>
            ))}

            <button onClick={() => setRows(rows.concat([""]))}>
                + add row
            </button>
        </>
    );
}
1
Raj Kumar 18 Feb. 2020 im 07:36

Ohne Index können wir die Karte verwenden und der Kartenabruf ist schneller, unter dem Code, den Sie ausprobieren können.

import React, { useState } from "react";

export default function() {
    const [rows, setRows] = useState(new Map());

    const onUpdate = (key, value) => {
        setRows(prev => new Map(prev).set(key, { key, value}));
    }
    const onDelete = (key) => {
        setRows(prev => new Map(prev).delete(key));
    }
    return (
        <>
            {[...rows].map((row, index) => (typeof row[1].value !== "undefined") && (
                <div key={index}>
                    <input value={row[1].value} onChange={e =>  onUpdate(row[1].key, e.target.value)} />
                    <button onClick={() => onDelete(row[1].key)}>- delete row</button>
                </div>
            ))}

            <button onClick={() => onUpdate(rows.size, "")}>
                + add row
            </button>
        </>
    );
}
-2
Suraj Kumar 18 Feb. 2020 im 13:04