You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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可观察对象。

修复步骤:

  1. 将数组内的对象转为MobX可观察对象
    修改ItemStore中的setItems方法,把每个原始对象包装成可观察对象:

    import {makeAutoObservable, observable} from 'mobx';
    
    // 更新ItemStore的setItems方法
    setItems: function (vals: ItemShape[]) {
      this.items = vals.map(item => observable(item));
    },
    
  2. 或通过创建新对象触发追踪
    在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);
    },
    
  3. 为FlatList配置keyExtractor(推荐)
    添加keyExtractor确保React能正确识别列表项的身份,避免渲染异常:

    <FlatList
      data={itemStore.items}
      keyExtractor={(item) => item.id.toString()}
      renderItem={({item}) => _renderItem(item)}
    />
    

原理说明

MobX通过追踪可观察对象的引用变化或可观察属性的修改触发组件更新。直接修改原始对象属性时,MobX无法感知变化;将对象转为可观察对象,或创建新对象替换原项,能让MobX正确捕获状态变更,进而触发组件重新渲染。


内容的提问来源于stack exchange,提问作者Kearney Taaffe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 20:03:12