¿Cómo restablecería completamente un valor en una tienda en SolidJS?
Tengo algo parecido a:
interface Item { id: number, price: number, quantity: number } interface State { items: Array<Item> } export const ItemsContext = createContext() export const ContextProvider = (props: any) => { const [state, setState] = createStore({items: []}) const incrementItemQuantity = ({id}: Item) => { const index = state.items.findIndex(i => i.id === id) if(index !== -1) { const item = state.items[index] setState("items", index, {quantity: item.quantity + 1}) } } const clearItems = () => { setState(produce(s => s.items = [])) } const addItem = (item: Item) => { setState(produce(s => s.items.push(item)) } const value = [state, { addItem, clearItems, incrementItemQuantity} ] return ( <ItemsContext.Provider value={value} > { props.children } <ItemsContext.Provider/> ) }Agregar un artículo e incrementar su cantidad funciona como se esperaba. Cuando yo:
Espero que el estado esté en blanco. Sin embargo, si agrego un elemento con las mismas propiedades que el primero a la lista, se muestra con los valores anteriores.
No puedo entender por qué. ¿Qué no estoy haciendo bien?
No estás usando la API de la tienda correctamente. Por ejemplo, la ruta del elemento le proporciona el elemento, primero debe obtener el elemento, luego actualizarlo a través de un setter:
setState("items", index, {quantity: item.quantity + 1});Así es como puedes hacerlo correctamente:
// Here path gives us the item setState("items", index, item => ({...item, quantity: item.quantity + 1})); // Here path gives us the property setState('items', index, 'quantity', q => q + 1);Aquí sabrás como podrás hacerlo. No expongo tienda sino artículos. Es tu decision.
// @refresh reload import { createContext, JSX, useContext } from "solid-js"; import { createStore, produce } from 'solid-js/store'; import { render } from "solid-js/web"; interface Item { id: number, price: number, quantity: number } interface Store { items: () => Array<Item>; add?: (item: Item) => void; increment?: (index: number) => void; clear?: () => void; }; export const CartContext = createContext<Store>(); export const CartProvider = (props: { children: JSX.Element }) => { const [store, setStore] = createStore({ items: [{ id: 0, price: 10, quantity: 1 }] }) const items = () => store.items; const add = (item: Item) => setStore('items', items => [...items, item]); const increment = (index: number) => setStore('items', index, 'quantity', q => q + 1); const clear = () => setStore('items', []); return ( <CartContext.Provider value={{ items, add, increment, clear }}> {props.children} </CartContext.Provider> ); } const Child = () => { const { items, add, increment, clear } = useContext(CartContext); return ( <div> <ul> {items().map((item, index) => ( <li>{JSON.stringify(item)} <button onclick={() => increment(index)}>inc</button></li>) )} </ul> <div> <button onClick={() => add({ id: items().length, price: 10, quantity: 1 })}>Add Item</button> {` `} <button onClick={() => clear()}>Clear Items</button> </div> </div> ) }; const App = () => { return ( <CartProvider> <Child /> </CartProvider> ); } render(App, document.querySelector("#app"));No estás usando la tienda correctamente. Mira este ejemplo en vivo aquí
import { render } from "solid-js/web"; import { createContext, useContext, For } from "solid-js"; import { createStore } from "solid-js/store"; export const CounterContext = createContext([{ items: [] }, {}]); export function CounterProvider(props) { const [state, setState] = createStore({ items: props.items || []}); const store = [ state, { add: (val) => setState("items", (c) => [...c, val]), clear: () => setState("items", () => []), }, ]; return ( <CounterContext.Provider value={store}> {props.children} </CounterContext.Provider> ); } const Counter = () => { const [state, { add,clear }] = useContext(CounterContext); return <> <For each={state.items}> {(i) => (<h1>{i}</h1>)} </For> <button onClick={() => add(state.items.length + 1)}>Add </button> <button onClick={clear}>Clear </button> </> }; const App = () => ( <CounterProvider> <Counter /> </CounterProvider> ); render(() => <App />, document.getElementById("app")!);