I have React Native app with MobX store. And i use useEffect hook to call fetch action from MobX to get data from API. The rendering is pretty strange. It looks like this:
useEffect call MobX action with fetch -> loading data, but can not render, the loading is not stopping -> push the button and change the navigation stack -> the data is appearing on a previous screen where before it could not rendered -> come back to the previous screen and see the data that before could not came. It means only when the navigation stack is changing the data is rendering. It looks like a problem with change MobX state. Can you help me please.
MobX state:
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())
Render component:
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 }
In my case it was, because i put all fetch functions to the one hook and call it in useEffect. In the end i have found the decision. I changes my function component to the class component and split all fetch functions in MobX store. Maybe it will be helpful for somebody: MobX store:
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
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.