I have a React.js app with MobX for state management. Here is the ItemStore class:
class ItemStore {
@observable items: IItem[] = []
@action loadItems = () => {
this.items = [
{
name: 'BeyBlade',
category: 'Toy',
amount: 5
},
{
name: 'Legos',
category: 'Toy',
amount: 10
},
{
name: 'Coka Cola',
category: 'Food',
amount: 8
},
{
name: 'Gummy Bears',
category: 'Food',
amount: 13
}
]
}
}
export default createContext(new ItemStore());
App.tsx:
function App() {
const itemStore = useContext(ItemStore);
const { loadItems } = itemStore;
return (
<Fragment>
<Container>
<Button content='Load Items' onClick={() => loadItems()} />
<ItemList />
</Container>
</Fragment>
);
}
export default observer(App);
When the button is pressed, supposedly 'loadItems' action runs and populates 'items' observable, and ItemList component re-renders to showcase the items. The problem occurs when I press the button. In the MobX dev tool you can clearly see the four items were loaded successfully, but ItemList doesn't re-render. However, if I add the 'items' observable in the deconstructed itemStore like this:
const { items, loadItems } = itemStore;
Boom, ItemList reloads with the items when the button is clicked!
But I know this shouldn't be the case, because when compiled it gives warning
Line 11:11: 'items' is assigned a value but never used
And also, in the tutorial source code I am referring to, the whole deconstructing is omitted there's nothing in App component that interacts with items directly.
I put observer in all components, so they can react to state changes. I really would like to know what's causing the ItemList to not re-render after a state change, and why explicitly bringing 'items' observable in the App.tsx fixed the issue, when in theory it shouldn't matter.
Thank you all, stay safe & happy!
EDIT-------------------------------
Here is ItemList.tsx also, thank you:
export const ItemList = () => {
const itemStore = useContext(ItemStore);
const {items} = itemStore;
return (
<Segment clearing>
<Item.Group divided>
{items.map(item => (
<Item key={item.name}>
<Item.Content>
<Item.Header>{item.name}</Item.Header>
<Item.Description>
Category: {item.category}, Amount: {item.amount}
</Item.Description>
</Item.Content>
</Item>
))}
</Item.Group>
</Segment>
)
}
export default observer(ItemList);
For the price of concussion from two days of banging my head against the wall, I found why!
For a (functional) React component to be able to 'observe' and apply state changes to itself, it needs to be exported as a higher-order observer function that takes the component as the parameter:
export const RandomComponent = () => {
return (
<div>Hello world!</div>
)
}
export default observer(RandomComponent);
In the example component above, I allowed a lenience for mistake by specifying that the not-observer RandomComponent can also be exported. When I export RandomComponent instead of observer(RandomComponent), I am exporting a version of the component that cannot 'observe' MobX state changes.
My mistake was leaving the component just like above and exporting { RandomComponent } instead of the default export.
I hope I am the only newbie making this mistake, but hope anyone find this useful:D
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.