Estoy creando una aplicación React que incluye un componente separado para la funcionalidad CRUD de los Productos y otro componente separado para la funcionalidad CRUD de los Proveedores.
Estoy usando el mismo método saveData para ambos componentes (la funcionalidad Crear de CRUD... que se activa cuando el Usuario presiona Guardar después de completar los campos de entrada de Producto o Proveedor). El método saveData se encuentra en un archivo ProductsAndSuppliers.js central que está disponible para los componentes de Productos y Proveedores.
En ambos componentes Producto y Proveedor, hay una tabla que muestra los Productos o Proveedores ya presentes como datos ficticios. Hice un botón en la parte inferior de cada página para agregar un nuevo Producto o Proveedor... según la pestaña que el usuario haya seleccionado en el lado izquierdo de la pantalla (Producto o Proveedor).
Dado que estoy usando el mismo método saveData en ambos casos, tengo el mismo problema cada vez que intento agregar un nuevo Producto o Proveedor a cada tabla respectiva después de completar los campos de entrada. Mi nuevo Producto o Proveedor se agrega... pero dos veces y no puedo entender por qué.
Intenté usar un operador de propagación para agregar el nuevo elemento a la colección, pero no tuve éxito:
saveData = (collection, item) => { if (item.id === "") { item.id = this.idCounter++; this.setState((collection) => { return { ...collection, item } }) } else { this.setState(state => state[collection] = state[collection].map(stored => stored.id === item.id ? item : stored)) } }Aquí está mi método saveData original que agrega el nuevo Producto o Proveedor, pero dos veces:
saveData = (collection, item) => { if (item.id === "") { item.id = this.idCounter++; this.setState(state => state[collection] = state[collection].concat(item)); } else { this.setState(state => state[collection] = state[collection].map(stored => stored.id === item.id ? item : stored)) } }mi estado se ve así:
this.state = { products: [ { id: 1, name: "Kayak", category: "Watersports", price: 275 }, { id: 2, name: "Lifejacket", category: "Watersports", price: 48.95 }, { id: 3, name: "Soccer Ball", category: "Soccer", price: 19.50 }, ], suppliers: [ { id: 1, name: "Surf Dudes", city: "San Jose", products: [1, 2] }, { id: 2, name: "Field Supplies", city: "New York", products: [3] }, ] }Hay problemas con ambas implementaciones.
Empezando por el de arriba:
// don't do this this.setState((collection) => { return { ...collection, item } }) En este caso, collection es el estado de su componente y le está agregando una propiedad llamada item . Obtendrás esto como resultado:
{ products: [], suppliers: [], item: item }La forma correcta de hacer esto con el operador de propagación es devolver un objeto que represente la actualización de estado. Puede usar un nombre de propiedad calculado para apuntar a la colección adecuada:
this.setState((state) => ({ [collection]: [...state[collection], item] }) )* Tenga en cuenta que tanto este ejemplo como el siguiente utilizan la función de retorno implícito de las funciones de flecha. Tenga en cuenta los paréntesis alrededor del objeto.
En el segundo ejemplo de código, estás
// don't do this this.setState(state => state[collection] = state[collection].concat(item) );Las expresiones de asignación devuelven el valor asignado, por lo que este código devuelve una matriz en lugar de un objeto y, francamente, me sorprendería si funcionara.
La implementación correcta es la misma que la anterior, excepto que usa concat en lugar de spread para crear la nueva matriz:
this.setState(state => ({ [collection]: state[collection].concat(item) }) ); const nextId = (function idGen (start = 100) { let current = start; return () => current++; })(100); console.log(nextId()); // 100 console.log(nextId()); // 101 console.log(nextId()); // 102 // ---------------- // a literal generator, just for fun const ids = (function* IdGenerator(start = 300) { let id = start; while (true) { yield id++; } })(); console.log(ids.next().value); // 300 console.log(ids.next().value); // 301 console.log(ids.next().value); // 302