Tengo un posible árbol de categorías infinitas y me gustaría agregar, actualizar o eliminar categorías en cualquier nivel con setState en reaccionar. Sé que esto es posible con la recursión, pero no tengo suficiente experiencia para manejar este problema por mi cuenta. Así es como podrían verse los datos:
const categories = [ { id: "1", name: "category1", subCategories: [ { id: "sub1", name: "subcategory1", subCategories: [ { id: "subsub1", name: "subsubcategory1", subCategories: [] }, { id: "subsub2", name: "subsubcategory2", subCategories: [] } ] }, { id: "sub2", name: "subcategory2", subCategories: [] } ] }, { id: "2", name: "category2", subCategories: [] } ]Teniendo en cuenta que su objeto de categorías de nivel superior es un objeto y no una matriz, la función de agregar y eliminar podría ser la siguiente (el mismo patrón para la actualización)
function add (tree, newCategory, parentId) { if(tree.id === parentId) return { ...tree, subCategories: tree.subCategories.concat(newCategory) } return { ...tree, subCategories: tree.subCategories.map(c => add(c, newCategory, parentId)) } } function remove (tree, idToRemove) { if(tree.subCategories.map(c => c.id).includes(idToRemove)) return { ...tree, subCategories: tree.subCategories.filter(c => c.id !== idToRemove) } return { ...tree, subCategories: tree.subCategories.map(c => remove(c, idToRemove)) } }así es como se vería la función recursiva. los argumentos:
id: id a buscar
gatos: la matriz de categorías para hacer un bucle
nestSubCategory: (booleano) si queremos agregar el objeto de subcategoría en la matriz de subcategorías o no
subCategoría: el objeto de categoría que queremos insertar
const addCategories = (id, cats, nestSubCategory, subCategory)=> { const cat = cats.find(item=> item.id === id) const arrSubs = cats.filter(item => item.subCategories?.length) .map(item => item.subCategories) if(cat){ if(nestSubCategory){ cat.subCategories.push(subCategory) return }else{ cats.push(subCategory) return } } else{ return addCategories(id, arrSubs[0], nestSubCategory, subCategory) } } addCategories("blabla1", categories, true, { id: "blabla2", name: "blablacategory1", subCategories: [] }) //console.log(categories) console.log( JSON.stringify(categories) )recuerde actualizar el objeto en el estado reemplazando toda la matriz de categorías una vez que se ejecuta la función. cuidado con la recursividad 🖖🏽
puedes hacer de manera similar para eliminar elementos, te dejo el placer de experimentar
Para actualizar una propiedad anidada de forma inmutable, debe copiar o realizar operaciones inmutables en todos sus padres.
Establecer una propiedad en un objeto anidado:
return { ...parent, person: { ...parent.person, name: 'New Name' } } Matrices: puede clonar previamente la matriz o usar una combinación de .slice() , .map() , .filter() y el operador de concatenación ( ... ); Advertencia: .splice muta la matriz.
(Este puede ser un tema largo, así que solo di una descripción general muy rápida)
Como esto puede volverse muy feo rápidamente en objetos con anidamiento profundo, el uso de immer lib se convierte en una necesidad en algún momento. Immer "crea un nuevo estado inmutable a partir de mutaciones".
const newState = immer(oldState, draft => { draft[1].subcategories[3].subcategories[1].name = 'Category' })En el caso extremo, puede combinar immer con lodash para crear mutaciones en lugares arbitrarios:
import set from 'lodash/set' const newState = immer(oldState, draft => { set(draft, [0, 'subcategories', 5, 'subcategories', 3], { id: 5, name:'Cat' }) })El sitio web "Es posible que no necesite lodash" tiene la implementación recursiva para lodash/set. Pero, en serio, solo usa lodash.
MÁS:
createNextState (consulte los documentos con cuidado).normalizr (charla larga).