Creo que mi problema se origina en la función disableButton , pero no puedo entender qué es lo que está mal
si la suma de todos los valores de cada contenido es igual a cero, lo que se puede comprar debe ser falso, lo que significa que el botón debe estar deshabilitado, pero incluso cuando agrego contenido al carrito, todavía está deshabilitado y, a veces, es necesario obtener una cantidad específica de valores para hacer el botón no está deshabilitado y luego vuelve a estar deshabilitado después, cualquier ayuda sería apreciada :)
const App = props => { const [items, setItems] = useState({ contents: { bacon: 0, cheese: 0, }, purchasable: false, /* this is to set the disabled state of the purchase button to true || false */ // ... }) /* i set my states this way to avoid calling const multiple times is that a bad practice ? */ /* function gets an outdated content so it takes a parameter from the 2 buttons that are going to be updating the state the most adding and removing functions */ const disableButton = (updatedContent) => { const contentsSum = Object.values(updatedContent).reduce((acc, curr) => (acc + curr), 0) setItems(items => ({ ...items, purchasable: contentSum > 0 /* idk if something is wrong with this "check" as button gets disabled even when cart isnt empty */ })) } /* this is to add contents to a cart */ const addContent(type) => { updatedContents = {...items.contents} updatedContents[type] = contentCount + 1 setItems(items => ({ ...items, content: updatedContents })) disableButton(updatedContent) } /* this removes content from the cart as long as it isnt empty */ const removeContent(type) => { const contentCount = items.contents[type] if(contentCount < 0) return updatedContents = {...items.contents} updatedContents[type] = contentCount - 1 setItems(items => ({ ...items, content: updatedContents })) disableButton(updatedContents) } return ( <div> <ContentControls purchasable={items.purchasable} /> /* the purchasable state is passes to a "place order" that gets disabled based on items.purchasable's state */ </div> ) };Como no puedo comentar todavía, tendré que ponerlo aquí. Uno, parece que contentCount no está definido en addContent. Así que estás configurando
updatedContent[type] = undefined + 1Que creo que es NaN. Esto podría causar problemas en su función disabledButton. Además, en su función removeContent está verificando si el valor es menor que cero, lo que creo que debería verificar si es menor o igual a cero, o mayor que cero.
Además, como dijo un comentarista anterior, podría agregar un useEffect como elementos como una dependencia y actualizar el estado adquirible allí. Adquirible debe ser su propio estado como se muestra en la referencia proporcionada por otro comentarista, lo que reduciría la complejidad y la sintaxis menos extendida.
Editar: Así que aquí hay un jfiddle básico que describe lo que estás tratando de hacer. https://jsfiddle.net/9v3cesfg/
Como puede ver, separé los elementos de la lógica adquirible. Probablemente haya una mejor manera de crear las listas de elementos, pero está bien por ahora. En lugar de llamar a una función cada vez que se cambia la lista como lo hizo en su ejemplo, la lógica ahora está en una función useEffect que se ejecuta cada vez que cambia la lista de elementos. Puede ver cuán simple es la lógica para determinar si los artículos se pueden comprar desde que separó los datos.
Un par de notas sobre esto. La clonación se realiza en el recuento de agregar y eliminar debido a cómo se definen y pasan los objetos en javascript. Cuando establece una const o variable igual a un objeto definido previamente, en realidad está configurando la const a una referencia de ese objeto. Entonces, si muta una propiedad en constante, entonces está mutando la misma propiedad en la constante original. La sintaxis extendida copia el objeto/matriz en lugar de hacer referencia a él.
Otra nota es sobre la clave para el div dentro de la función de mapa que se establece en Math.random(). Nunca haría esto en una aplicación real. React usa la clave para administrar sus eventos DOM, por lo que siempre deben ser únicos sin posibilidad de claves duplicadas. En su lugar, usaría una biblioteca como UUID que genera sistemáticamente claves únicas
Muy bien, gracias a todos... seguí el consejo de Mason y usé useEffect , luego me di cuenta de que el problema estaba en la forma en que la propiedad de entrada html disabled obtiene su valor. El botón se deshabilita porque contentSum es mayor que 0, lo cual es true , por lo tanto, establece el estado deshabilitado para el botón "realizar pedido" en verdadero cuando el carrito no está vacío. gracias Mason :) Y me di cuenta de que a mi código le faltaban algunos bits, lo siento.
const App = props => { const [items, setItems] = useState({ contents: { bacon: 0, cheese: 0, }, purchasable: false, /* this is to set the disabled state of the purchase button to true or false [edit: this is to be set to true by default not false] */ // ... }) /* i set my states this way to avoid calling const multiple times, is that a bad practice ? */ /* function gets an outdated content so it takes a parameter from the 2 functions that are going to be updating the state || contents state the most the adding and removing functions */ const disableButton = (updatedContent) => { const contentsSum = Object.values(updatedContent).reduce((acc, curr) => (acc + curr), 0) setItems(items => ({ ...items, purchasable: contentSum > 0 /* idk if something is wrong with this "check" as button gets disabled even when cart isnt empty [edit: nothing was wrong with the check, it was doing its job. i just needed to invert the boolean result to suit the value that the disabled state would accept ie !contentSum > 0] */ })) } /* this is to add contents to a cart */ const addContent(type) => { const oldContentCount = items.contents[type] const updatedContents = {...items.contents} updatedContents[type] = oldContentCount + 1 setItems(items => ({ ...items, content: updatedContents })) disableButton(updatedContent) } /* this removes content from the cart as long as it isnt empty */ const removeContent(type) => { const oldContentCount = items.contents[type] const updatedContents = {...items.contents} updatedContents[type] = oldContentCount > 0 ? oldContentCount - 1 : 0 setItems(items => ({ ...items, content: updatedContents })) disableButton(updatedContents) } return ( <Aux> /* the purchasable state is passes to a "place order" button that gets disabled based on items.purchasable's state */ <ContentControls purchasable={items.purchasable} /> </Aux> ) };