¿Método push en React Hooks (useState)?


Respuestas:


264

Cuando lo usa useState, puede obtener un método de actualización para el elemento de estado:

const [theArray, setTheArray] = useState(initialArray);

luego, cuando desee agregar un nuevo elemento, use esa función y pase la nueva matriz o una función que creará la nueva matriz. Normalmente esto último, dado que las actualizaciones de estado son asincrónicas y, a veces, por lotes:

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

A veces puede salirse sin usar ese formulario de devolución de llamada, si solo actualiza la matriz en los controladores para ciertos eventos de usuario específicos como click(pero no como mousemove):

setTheArray([...theArray, newElement]);

Los eventos para los que React asegura que el renderizado se vacíe son los "eventos discretos" enumerados aquí .

Ejemplo en vivo (pasando una devolución de llamada a setTheArray):

Debido a que la única actualización que theArrayhay es la de un clickevento (uno de los eventos "discretos"), podría salirme con una actualización directa en addEntry:


1
... e intente setTheArray(currentArray => [...currentArray, newElement])si lo anterior no funciona. Lo más probable es en useEffect(...theArray..., []), es importante darse cuenta de que theArrayes una constante, por lo que las actualizaciones funcionales son necesarios para los valores de futuro renders
— Aprillion

@Aprillion: ¿No estás seguro de lo que estás diciendo con ese useEffectejemplo ...?
— TJ Crowder

1
Si useEffecttiene una lista de dependencias vacía [], se ejecutará solo durante el primer renderizado. Entonces el valor del theArrayinterior del efecto siempre será initialArray. En situaciones en las setTheArray([...initialArray, newElement])que no tendría sentido, y cuando la theArrayconstante siempre será igual a initialValue, se necesitan actualizaciones funcionales.
— Aprillion

@Aprillion - Me temo que todavía no lo entiendo, posiblemente sea un poco denso. :-) ¿Por qué necesitarías un efecto con solo el valor de la matriz inicial ? (Quiero decir, puede haber un caso de uso poco frecuente, pero ...) E incluso si lo hace, ¿qué tiene que ver con la pregunta?
— TJ Crowder

Hola @TJCrowder, utilizo la forma de devolución de llamada para fusionar datos antiguos con nuevos cuando obtengo datos, pero por alguna razón no funciona correctamente, ¿puedes marcar esto para comprender mi problema?
— Oliver D

45

Para expandir un poco más, aquí hay algunos ejemplos comunes. Empezando con:

const [theArray, setTheArray] = useState(initialArray);
const [theObject, setTheObject] = useState(initialObject);

Empuje el elemento al final de la matriz

setTheArray(prevArray => [...prevArray, newValue])

Insertar / actualizar elemento al final del objeto

setTheObject(prevState => ({ ...prevState, currentOrNewKey: newValue}));

Insertar / actualizar elemento al final de la matriz de objetos

setTheArray(prevState => [...prevState, {currentOrNewKey: newValue}]);

Empuje el elemento al final del objeto de las matrices

let specificArrayInObject = theObject.array.slice();
specificArrayInObject.push(newValue);
const newObj = { ...theObject, [event.target.name]: specificArrayInObject };
theObject(newObj);

Aquí también hay algunos ejemplos prácticos. https://codesandbox.io/s/reacthooks-push-r991u


4
Gracias por todos los ejemplos. Exactamente con lo que estaba teniendo un problema era con su elemento Push al final del objeto de las matrices . Probé tantas cosas diferentes, pero no pude improvisarlas.
— sdouble

5

De la misma manera que lo haces con el estado "normal" en los componentes de la clase React.

ejemplo:

function App() {
  const [state, setState] = useState([]);

  return (
    <div>
      <p>You clicked {state.join(" and ")}</p>
      //destructuring
      <button onClick={() => setState([...state, "again"])}>Click me</button>
      //old way
      <button onClick={() => setState(state.concat("again"))}>Click me</button>
    </div>
  );
}

esto funcionará con onClick, pero el setState (oldState => [... oldState, pushsomething]) es cómo debe hacerlo
— Cyrus Zei

3
// Save search term state to React Hooks with spread operator and wrapper function

// Using .concat(), no wrapper function (not recommended)
setSearches(searches.concat(query))

// Using .concat(), wrapper function (recommended)
setSearches(searches => searches.concat(query))

// Spread operator, no wrapper function (not recommended)
setSearches([...searches, query])

// Spread operator, wrapper function (recommended)
setSearches(searches => [...searches, query])

https://medium.com/javascript-in-plain-english/how-to-add-to-an-array-in-react-state-3d08ddb2e1dc


2

setTheArray([...theArray, newElement]);es la respuesta más simple, pero tenga cuidado con la mutación de elementos en el Array . Utilice la clonación profunda de elementos de matriz.


La clonación profunda que mencionas, ¿significa recibir como objA? UseState y concat el objA con objB? ¿Igual que este enlace? gist.githubusercontent.com/kahsing/…
— Luiey

1

El método más recomendado es usar la función de envoltura y el operador de extensión juntos. Por ejemplo, si ha inicializado un estado llamado nameasí,

const [names, setNames] = useState([])

Puede empujar a esta matriz de esta manera,

setNames(names => [...names, newName])

Espero que ayude.


No publique respuestas que solo incluyan enlaces. El vínculo podría romperse en el futuro. En su lugar, cree una reseña de ese artículo y asegúrese de responder la pregunta.
— BlackCetha

Si bien este enlace puede responder la pregunta, es mejor incluir aquí las partes esenciales de la respuesta y proporcionar el enlace como referencia. Las respuestas de solo enlace pueden dejar de ser válidas si cambia la página enlazada. - De la revisión
— ilke444

0

Probé los métodos anteriores para insertar un objeto en una matriz de objetos en useState pero tuve el siguiente error al usar TypeScript :

Escriba 'TxBacklog [] | undefined 'debe tener un método' Symbol.iterator 'que devuelva un iterator.ts (2488)

La configuración de tsconfig.json aparentemente era correcta:

{
   "compilerOptions": {
   "target": "es6",
   "lib": [
      "dom",
      "dom.iterable",
      "esnext",
      "es6",
],

Esta solución resolvió el problema (mi código de muestra):

Interfaz:

   interface TxBacklog {
      status: string,
      txHash: string,
   }

Variable de estado:

    const [txBacklog, setTxBacklog] = React.useState<TxBacklog[]>();

Empuje un nuevo objeto en la matriz:

    // Define new object to be added
    const newTx = {
       txHash: tx,
       status: 'pending'
    };
    // Push new object into array
    (txBacklog) 
       ? setTxBacklog([...txBacklog, newTx])
       : setTxBacklog([newTx]);

Leí otras alternativas como agregar '!' al nuevo objeto, pero no funcionó tan bien.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.