Mobx/React Native问题:状态变更后组件未更新
React Native + MobX 组件不更新问题
我正在尝试创建一个简单的React Native + MobX示例,Web端可正常运行,但React Native端遇到问题:点击Item List中的绿色勾选按钮后,后台日志显示商品数量已递减、商品已加入购物车,但Item List组件并未重新渲染展示更新后的数量。
相关代码
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()} </> ); });
日志信息
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"}]
问题核心
状态已在MobX store中更新,但React Native组件未触发重新渲染,使用纯函数式开发(无类、装饰器)。
解决方案
问题出在MobX无法追踪原始对象属性的变化,因为你直接修改了数组中对象的quantity属性,而这些原始对象并非MobX可观察对象。
修复步骤:
将数组内的对象转为MobX可观察对象
修改ItemStore中的setItems方法,把每个原始对象包装成可观察对象:import {makeAutoObservable, observable} from 'mobx'; // 更新ItemStore的setItems方法 setItems: function (vals: ItemShape[]) { this.items = vals.map(item => observable(item)); },或通过创建新对象触发追踪
在removeItem和addItem中,不要直接修改属性,而是生成新对象替换原数组中的项:removeItem: function (id: number): void { console.log(`[ItemStore]:removeItem removing ${id}`); this.items = this.items.map(item => item.id === id ? {...item, quantity: item.quantity - 1} : item ); console.log(this.items); }, addItem: function (id: number) { console.log(`[ItemStore]:addItem adding ${id}`); this.items = this.items.map(item => item.id === id ? {...item, quantity: item.quantity + 1} : item ); console.log(this.items); },为FlatList配置keyExtractor(推荐)
添加keyExtractor确保React能正确识别列表项的身份,避免渲染异常:<FlatList data={itemStore.items} keyExtractor={(item) => item.id.toString()} renderItem={({item}) => _renderItem(item)} />
原理说明
MobX通过追踪可观察对象的引用变化或可观察属性的修改触发组件更新。直接修改原始对象属性时,MobX无法感知变化;将对象转为可观察对象,或创建新对象替换原项,能让MobX正确捕获状态变更,进而触发组件重新渲染。
内容的提问来源于stack exchange,提问作者Kearney Taaffe
相关产品推荐
相关产品推荐

