I'm trying to create a simple React-Native MobX example-here's the working web example here
// App.tsx
const apiGetItems = async () => {
return await new Promise(resolve => {
resolve([
{id: 1, title: 'eggs', quantity: 10},
{id: 2, title: 'bread', quantity: 10},
{id: 3, title: 'milk', quantity: 10},
{id: 4, title: 'coffee', quantity: 10},
]);
});
};
export const rootStore = createRootStore();
const App = (): JSX.Element => {
useEffect(() => {
apiGetItems()
.then(rootStore.itemStore.setItems)
.catch((err: Error) => {
console.log('whoops!', err);
});
}, []);
return (
<>
<SafeAreaView style={styles.container}>
<View style={styles.item}>
<ShoppingCart />
</View>
<View style={styles.item}>
<ItemList />
</View>
</SafeAreaView>
</>
);
};
export {App};
// ItemStore.tsx
import {makeAutoObservable} from 'mobx';
import {type ItemShape, type ItemStoreShape} from '../interfaces';
export const ItemStore = (): ItemStoreShape => {
return makeAutoObservable({
items: [] as ItemShape[],
setItems: function (vals: ItemShape[]) {
this.items = vals;
},
getItems: function (): ItemShape[] {
return this.items;
},
removeItem: function (id: number): void {
console.log(`[ItemStore]:removeItem removing ${id}`);
const it = this.items.find((item: ItemShape) => item.id === id);
if (it !== undefined) {
it.quantity--;
}
console.log(this.items);
},
addItem: function (id: number) {
console.log(`[ItemStore]:addItem adding ${id}`);
const it = this.items.find((item: ItemShape) => item.id === id);
if (it !== undefined) {
it.quantity++;
}
console.log(this.items);
},
});
};
// ItemList.tsx
import React from 'react';
import {ItemShape, type RootStoreShape} from '../interfaces';
import {observer} from 'mobx-react-lite';
import {rootStore} from '../../App';
import {Button, FlatList, Text} from 'react-native';
export const ItemList = observer((): JSX.Element => {
const {itemStore, cartStore}: RootStoreShape = rootStore;
const addItemToCart = (itemIndex: number, itemTitle: string): void => {
itemStore.removeItem(itemIndex);
cartStore.addItem(itemIndex, itemTitle);
};
const renderItemsNative = (): JSX.Element => {
if (itemStore.items.length === 0) {
return <></>;
}
const _renderItem = (item: ItemShape) => (
<Text>
( {item.id} ) {item.title} - {item.quantity}
<Button
title={'✅'}
onPress={() => addItemToCart(item.id, item.title)}
/>
</Text>
);
return (
<FlatList
data={itemStore.items}
renderItem={({item}) => _renderItem(item)}
/>
);
};
return (
<>
<Text>Item List</Text>
{renderItemsNative()}
</>
);
});
I have added logs and can see that the state is changing, but the components are not being re-rendered with new values.
I'm trying to do this using all functional code (no classes, no decorators, etc). Here's the gitHub repo (seems too big to paste here).
But, basically, on clicking the green checkmark button in the "Item List", the item quantity decrements, the item is added to the "Shopping Cart", but the new quantity isn't being shown in the "Item List"
Here's some logs
LOG [ItemStore]:removeItem removing 1
LOG [{"id": 1, "quantity": 9, "title": "eggs"}, {"id": 2, "quantity": 10, "title": "bread"}, {"id": 3, "quantity": 10, "title": "milk"}, {"id": 4, "quantity": 10, "title": "coffee"}]
LOG [CartStore]:addItem 1-eggs
LOG [{"id": 1, "quantity": 1, "title": "eggs"}]
// click button a second time
LOG [ItemStore]:removeItem removing 1
LOG [{"id": 1, "quantity": 8, "title": "eggs"}, {"id": 2, "quantity": 10, "title": "bread"}, {"id": 3, "quantity": 10, "title": "milk"}, {"id": 4, "quantity": 10, "title": "coffee"}]
LOG [CartStore]:addItem 1-eggs
LOG [{"id": 1, "quantity": 2, "title": "eggs"}]
I don't know if I'm missing something to make the state re-render or what, but, I'm lost and could use any help