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

React Native结合mobx-react-lite与Hooks实现API数据获取及FlatList渲染咨询

Hey there! Let's break down how to optimize your MobX setup for fetching data and rendering it in a FlatList. You're already on the right track with your DataStore and context setup, but we can tweak a few things to make it cleaner, more idiomatic to MobX, and ensure your component properly reacts to state changes.

Key Optimizations & Best Practices

1. Use makeAutoObservable Instead of decorate

MobX 6+ recommends using makeAutoObservable over the older decorate syntax—it automatically infers observables, actions, and computed values, reducing boilerplate code.

2. Use flow for Async Actions

MobX's flow utility is designed specifically for async operations. It replaces the need for async/await + runInAction by handling state updates in a transactional way under the hood.

3. Wrap Your Component with observer

Your functional component won't react to MobX state changes unless you wrap it with the observer HOC from mobx-react-lite. This is critical for getting your FlatList to update when data loads.

4. Enhance Error Handling & Loading State Rendering

Add clear error messaging for users and clean up conditional rendering to avoid showing both the loader and FlatList at the same time.


Modified Code Examples

Updated DataStore

import { createContext } from 'react'
import { makeAutoObservable, flow } from 'mobx'
import mapObjects from '../utils/mapObjects'

class DataStore {
  data = null
  error = null // Use null instead of false for clearer "no error" state
  loading = true

  constructor() {
    // Auto-configure observables, actions, and computed values
    makeAutoObservable(this, {
      fetchData: flow // Mark async function as a MobX flow action
    })
  }

  // Use generator function with flow for async logic
  fetchData = flow(function* (url) {
    this.data = null
    this.error = null
    this.loading = true

    try {
      const response = yield fetch(url)
      // Check for HTTP errors (fetch doesn't reject on 4xx/5xx by default)
      if (!response.ok) {
        throw new Error(`Request failed: ${response.status}`)
      }
      const jsonResponse = yield response.json()
      const obj = mapObjects(jsonResponse) // Remove await if mapObjects is sync

      // No need for runInAction—flow handles state updates automatically
      this.loading = false
      this.data = obj
    } catch (err) {
      this.loading = false
      this.error = err.message || 'Failed to load data'
      console.error('Fetch error:', err)
    }
  })

  // Simplified computed getters (optional but cleaner)
  get getData() { return this.data }
  get getError() { return this.error }
  get getLoading() { return this.loading }
}

export default createContext(new DataStore())

Updated ChartsScreen Component

import React, { useContext, useEffect } from 'react'
import { ActivityIndicator, FlatList, Platform, StyleSheet, View, Text } from 'react-native'
import DataStore from '../mobx/DataStore'
import { observer } from 'mobx-react-lite' // Required for reactive functional components
import { ChartsHeader, CryptoItem, IconsHeader, ProjectStatusBar } from '../components'
import { WP, HP } from '../constants'

const styles = StyleSheet.create({
  container: { flex: 1 },
  errorText: { color: '#dc2626', textAlign: 'center', marginTop: HP('2%'), fontSize: WP('4%') }
})

// Wrap component with observer to enable reactivity
const ChartsScreen = observer(({ navigation }) => {
  const { container, errorText } = styles
  const store = useContext(DataStore)
  const url = 'https://poloniex.com/public?command=returnTicker'

  useEffect(() => {
    store.fetchData(url)
  }, [store, url]) // Add dependencies to avoid unnecessary re-fetches

  const percentColorHandler = (number) => number >= 0

  // Show error state if something goes wrong
  if (store.error) {
    return (
      <View style={container}>
        {Platform.OS === 'ios' && <ProjectStatusBar />}
        <IconsHeader 
          header="Charts" 
          leftIconName="ios-arrow-back" 
          leftIconPress={() => navigation.navigate('Welcome')} 
        />
        <Text style={errorText}>{store.error}</Text>
      </View>
    )
  }

  return (
    <View style={container}>
      {Platform.OS === 'ios' && <ProjectStatusBar />}
      <IconsHeader 
        dataError={store.error} 
        header="Charts" 
        leftIconName="ios-arrow-back" 
        leftIconPress={() => navigation.navigate('Welcome')} 
      />
      <ChartsHeader />

      {/* Conditionally render loader OR FlatList */}
      {store.loading ? (
        <ActivityIndicator 
          animating 
          color="#068485" 
          style={{ top: HP('30%') }} 
          size="small" 
        />
      ) : (
        <FlatList 
          data={store.data} 
          keyExtractor={(item) => item.key} 
          renderItem={({ item }) => (
            <CryptoItem 
              name={item.key} 
              highBid={item.highestBid} 
              lastBid={item.last} 
              percent={item.percentChange} 
              percentColor={percentColorHandler(item.percentChange)} 
            />
          )} 
        />
      )}
    </View>
  )
})

export { ChartsScreen }

Additional Tips

  • Optimize List Items: Wrap your CryptoItem component with React.memo to prevent unnecessary re-renders when parent state changes.
  • Debounce Re-Fetches: If you ever need to re-fetch data on URL changes, add a debounce to avoid excessive API calls.
  • Normalize Data: If your API response is large, consider normalizing it (e.g., converting objects to arrays) to make FlatList rendering more efficient.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:10:11