Interface

  interface ListInterface {
    listName: string;
    list: string[];
  }

useState

  const [initialList, setinitialList] = useState<ListInterface>({listName: "List1", list:['One', 'Two', 'Three', 'Four', 'Five', 'Six']});
  const [selectedList, setSelectedList] = useState<ListInterface>(initialList);

Je sais comment ajouter de nouveaux éléments (push) au tableau. Mais avoir des problèmes lorsque le tableau est en objet / interface. Comment le faites-vous avec les hooks useState?

setTheArray(oldArray => [...oldArray, newElement]);

J'ai créé un exemple simple de bac à sable.

  • Utilisez le champ de saisie pour ajouter un nouveau texte au tableau selectedList.list

https://codesandbox.io/s/reacr-ts-nested-object-array-example-z1uyd?file=/src/App.tsx

1
CookieMonster 16 mars 2021 à 21:22

2 réponses

Meilleure réponse

Vous avez défini une interface d'objet, ce qui signifie que vous devez pousser un objet conforme à ce type chaque fois que vous souhaitez le mettre à jour.

  
  // ...

  const [text, setText] = useState<string>(''); // <--- set type and set to blank to remove type errors due to `text` being possibly undefined

  // ...

  const handleSubmit = (event: any) => {    
    event.preventDefault();
    console.log("Submitted: " + text);

    //setSelectedList({list: oldArray => [...oldArray, newElement]});
    // the above wont work because it is an array, but `ListInterface` is an object (you might want to change the name to `ListEntry` or `ListObject` to avoid confusion)

    setSelectedList({
      listName: selectedList.listName,
      list: [...selectedList.list, text]
    })

  };

Appréciez l'acceptation. Consultez également la réponse de @ axtck, car ils apportent quelques autres améliorations importantes à votre code!

3
Harley Lang 16 mars 2021 à 18:51

Vous ne devriez pas initialiser une variable d'état pour votre objet initial, vous pouvez simplement utiliser l'interface et le déclarer de cette façon:

const initialList: ListInterface = {
  listName: "List1",
  list: ["One", "Two", "Three", "Four", "Five", "Six"]
};

Puisque vous souhaitez uniquement mettre à jour la liste à l'intérieur de l'objet, vous pouvez utiliser functional setState() comme ceci:

const handleSubmit = (event: any) => {
  console.log("Submitted: " + text);
  event.preventDefault();

  setSelectedList((prevState) => {
    return { ...prevState, list: prevState.list = [...prevState.list, text] };
  });
};

Lorsque mapping, assurez-vous de passer un key valide:

{selectedList.list.map((item, i) => {
  return <h3 key={i}>{item}</h3>;
})}

Code complet et sandbox mis à jour:

import { useState } from "react";
import "./styles.css";

export default function App() {
  interface ListInterface {
    listName: string;
    list: string[];
  }

  const initialList: ListInterface = {
    listName: "List1",
    list: ["One", "Two", "Three", "Four", "Five", "Six"]
  };

  const [selectedList, setSelectedList] = useState<ListInterface>(initialList);
  const [text, setText] = useState("");

  const handleChange = (event: any) => {
    setText(event.target.value);
  };

  const handleSubmit = (event: any) => {
    console.log("Submitted: " + text);
    event.preventDefault();

    setSelectedList((prevState) => {
      return { ...prevState, list: prevState.list = [...prevState.list, text] };
    });
  };

  return (
    <div className="App">
      {selectedList.list.map((item, i) => {
        return <h3 key={i}>{item}</h3>;
      })}

      <form onSubmit={handleSubmit}>
        <label>
          Add To List:
          <input type="text" value={text} onChange={handleChange} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    </div>
  );
}
1
axtck 16 mars 2021 à 18:50