javascript - Mobx,React Native,从 API 获取数据后 mobx 突变状态的奇怪行为
问题描述
我有 MobX 商店的 React Native 应用程序。我使用 useEffect 挂钩从 MobX 调用 fetch 操作以从 API 获取数据。渲染很奇怪。它看起来像这样:
useEffect 使用 fetch 调用 MobX 操作 -> 加载数据,但无法渲染,加载并未停止 -> 按下按钮并更改导航堆栈 -> 数据出现在之前无法渲染的前一个屏幕上 -> 来回到上一屏,看到之前来不及的数据。这意味着仅当导航堆栈更改数据时才会呈现。更改 MobX 状态似乎有问题。你能帮我吗。
MobX 状态:
import { createContext } from 'react'
import { action, decorate, observable, computed, runInAction } from 'mobx'
import fetchData from '../utils/fetchData'
import mapObjects from '../utils/mapObjects'
class DataStore {
data = null
error = false
loading = true
get getData(){
return this.data
}
get getError(){
return this.error
}
get getLoading(){
return this.loading
}
async fetchData(url) {
this.data = null
this.error = false
this.loading = true
try {
console.log('TRY')
const response = await fetch(url)
const jsonResponse = await response.json()
const obj = await mapObjects(jsonResponse)
runInAction(() => {
console.log('WRITE!!!')
this.loading = false
this.data = obj
})
} catch (err) {
runInAction(() => {
console.log(err)
this.loading = false
this.error = err
})
}
}
}
decorate(DataStore, {
data: observable,
error: observable,
loading: observable,
fetchData: action
})
export default createContext(new DataStore())
渲染组件:
import React, { useContext, useEffect, useState } from 'react'
import { ActivityIndicator, FlatList, Platform, StyleSheet, View } from 'react-native'
import DataStore from '../mobx/DataStore'
import { autorun } from 'mobx'
import { ChartsHeader, CryptoItem, IconsHeader, ProjectStatusBar } from '../components'
import { useFetch } from '../hooks/useFetch'
import { WP, HP } from '../constants'
const styles = StyleSheet.create({
container: {
flex: 1
}
})
const ChartsScreen = ({ navigation }) => {
const { container } = styles
const store = useContext(DataStore)
const url = 'https://poloniex.com/public?command=returnTicker'
console.log('store', store)
useEffect(() => {
store.fetchData(url)
}, [])
//*Call custom hook and data distruction
//const { data, error, loading } = useFetch(url)
//*Change percent amount color depends on the amount
const percentColorHandler = number => {
return number >= 0 ? true : false
}
return (
<View style={container}>
{Platform.OS === 'ios' && <ProjectStatusBar />}
<IconsHeader
dataError={store.error}
header="Charts"
leftIconName="ios-arrow-back"
leftIconPress={() => navigation.navigate('Welcome')}
/>
<ChartsHeader />
<ActivityIndicator animating={store.loading} 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 }
解决方案
在我的情况下是这样,因为我将所有 fetch 函数放在一个钩子上并在 useEffect 中调用它。最后我找到了决定。我将我的函数组件更改为类组件并拆分 MobX 存储中的所有获取函数。也许它会对某人有所帮助: MobX 商店:
import { action, observable, runInAction } from 'mobx'
class DataStore {
@observable data = null
@observable error = false
@observable fetchInterval = null
@observable loading = false
//*Make request to API
@action.bound
fetchInitData() {
const response = fetch('https://poloniex.com/public?command=returnTicker')
return response
}
//*Parse data from API
@action.bound
jsonData(data) {
const res = data.json()
return res
}
//*Get objects key and push it to every object
@action.bound
mapObjects(obj) {
const res = Object.keys(obj).map(key => {
let newData = obj[key]
newData.key = key
return newData
})
return res
}
//*Main bound function that wrap all fetch flow function
@action.bound
async fetchData() {
try {
runInAction(() => {
this.error = false
this.loading = true
})
const response = await this.fetchInitData()
const json = await this.jsonData(response)
const map = await this.mapObjects(json)
const run = await runInAction(() => {
this.loading = false
this.data = map
})
} catch (err) {
console.log(err)
runInAction(() => {
this.loading = false
this.error = err
})
}
}
//*Call reset of MobX state
@action.bound
resetState() {
runInAction(() => {
this.data = null
this.fetchInterval = null
this.error = false
this.loading = true
})
}
//*Call main fetch function with repeat every 5 seconds
//*when the component is mounting
@action.bound
initInterval() {
if (!this.fetchInterval) {
this.fetchData()
this.fetchInterval = setInterval(() => this.fetchData(), 5000)
}
}
//*Call reset time interval & state
//*when the component is unmounting
@action.bound
resetInterval() {
if (this.fetchInterval) {
clearTimeout(this.fetchInterval)
this.resetState()
}
}
}
const store = new DataStore()
export default store
推荐阅读
- php - 如何扩展 Laravel Sanctum 的功能?
- html - RTL 子菜单未正确对齐
- c# - EF创建的数据库查询问题
- python - Python 类中的自我
- c++ - 具有 const 引用的 C++ Setter 成员函数在运行时导致“读取访问冲突”异常
- php - .htaccess 在数字海洋服务器中不起作用
- python - Google KickStart 错误答案
- javascript - 如何处理带有惰性和路由组件的 vue 组合 API?
- vert.x - 即使工作线程可用,Vertx Http Webclient 请求也会挂起
- tensorflow - 为什么在 Tensorflow 教程中将 sqrt(dim) 与 Transformer 的编码输入相乘?