jhonnymichel / react-hookstore

A state management library for react using the bleeding edge hooks feature

Home Page:https://codesandbox.io/s/r58pqonkop

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Complex Object updating state, not re-render function

sremiger1 opened this issue · comments

commented

When the object is complex it does not appear to be forcing state to re-render. Am I doing something wrong?
If you un comment the line //setCartListForce(!cartListForce); everything updates, if you leave it commented the quantity display never updates.

import React from 'react';
import { createStore, useStore } from 'react-hookstore';

export class ProductItem {
    key: number;
    ProductId?: number;
    ProductDescription!: string;
    SKU!: string;
    Price!: number;
    formatPrice() {
        return '$' + this.Price.toFixed(2).toString();
    }
}

export class CartItem extends ProductItem {
    Quantity: number = 0;
}


export class ShoppingCartList {
    key: number;
    cartItems!: CartItem[];
    getTotal(): string {
        let sum: number = 0;
        if (this.cartItems === null || this.cartItems.length === 0) {
            return '$' + sum.toFixed(2).toString();
        }

        let i: number = 0;
        for (i = 0; i < this.cartItems.length; i++) {
            let cartItem: CartItem = this.cartItems[i];
            if (cartItem.Price && cartItem.Quantity) {
                const itemTotal: number = cartItem.Price * cartItem.Quantity;
                sum += itemTotal;
            }
        }
        return '$' + sum.toFixed(2).toString();
    }
    getCartCount(): number {
        let total: number = 0;
        if (this.cartItems === null || this.cartItems.length === 0) {
            return 0;
        }

        let i: number = 0;
        for (i = 0; i < this.cartItems.length; i++) {
            let cartItem: CartItem = this.cartItems[i];
            if (cartItem.Quantity) {
                total += cartItem.Quantity;
            }
        }
        return total;
    }
}

const shoppingCartList: ShoppingCartList = new ShoppingCartList();
shoppingCartList.cartItems = [];
createStore('cartListX', shoppingCartList);
createStore('cartListForce', true);

export function Message() {
    const[cartList] = useStore<ShoppingCartList>('cartListX');
    const[cartListForce] = useStore<ShoppingCartList>('cartListForce');
    
    return (
        <div>
            { cartList.getCartCount() }
        </div>
    );
}

export default function Basic() {
    const[cartList, setCartList] = useStore<ShoppingCartList>('cartListX');
    const[cartListForce, setCartListForce ] = useStore<boolean>('cartListForce');
    const _onClick =() => {
        console.log('_onClick');
        if (cartList.cartItems.length == 0 ){
            console.log('_onClick add item');
            let cartItem: CartItem = new CartItem();
            cartItem.Price = 1.00;
            cartItem.Quantity = 1;
            cartList.cartItems.push( cartItem );
            
        }
        else{
            console.log('_onClick increment');
            cartList.cartItems[0].Quantity += 1;
        }
        console.log('_onClick setList');
        setCartList(cartList);
        //setCartListForce(!cartListForce);
    }
    return (
        <div>
            <button onClick={_onClick}>Click here to Add Quantity</button>
            <Message />
        </div>
    );
}
commented

That is normal within react. Objects and Arrays do not force re-renders as their references do not change.

That's exactly it. Thanks @caryd. You're using a class instance as your state. if you refactor it to be a plain object and replace the object everytime using destructuring assignment (For example: doing this setState({ ...oldState, keyToUpdate: newValue }) it will work.

If you wish to keep using this structure, I suggest using MobX to manage your state, it'll probably be great for you!

Also I have currently a PR opened for a new feature, where you'll be able to tell the library which bits of the state object you're using in each component, it would also help in this case.