When typing on the keyboard I was seeing some warnings about the input being ahead of the JS code..
Native TextInput(react native is awesome) is 4 events ahead of JS - try to make your JS faster.
So added the debounce and got this to "work":
...
import { debounce } from 'lodash'
...
export default class App extends React.Component {
constructor(props) {
super(props)
this.state = {
data,
indexRef: data.reduce((result, item, index) => {
result[item.title] = index
return result
}, {}),
ready: false,
}
this.updatePitch = this.updatePitch.bind(this)
this.saveLocally = debounce(this.saveLocally, 300).bind(this)
}
...
updatePitch(id, text) {
// Copy the data
let data = [...this.state.data]
const index = data.findIndex(obj => obj.id == id)
data[index].pitch = text
// Update the state
this.setState({ data }, this.saveLocally(data))
}
saveLocally(data) {
try {
AsyncStorage.setItem('data', JSON.stringify(data))
this.forceUpdate()
} catch (error) {
// Well..
}
}
render() {
...
BTW: I'm doing some "prop drilling" for now - but planning to do use the Context API (react 16.3)
The warning seems to have gone by adding debounce (1).. But I'm seeing some strange issues - particularly on the iPhone 8 plus simulator (not seeing the same on iPhone 6 simulator or Android device)
Issues observed:
TextInput don't expand - it just add scolling (expands on iPhone 6 and Android device)FlatList - seems like it has problems finding correct height of list elements..state and AsyncStorage?(1) One other way than using debounce could be to use getDerivedStateFromProps and add some sort of timer pushing the state to the parent component after some period of time.. But wasn't sure that this would make the JS code faster. So didn't try it.

I open sourced the entire code since it is too hard to give all the needed information in a SO post when the code is so nested.
The entire code is here: https://github.com/Norfeldt/LionFood_FrontEnd
(I know that my code might seem messy, but I'm still learning..)
I don't expect people to go in and fix my code with PR (even though it would be awesome) but just give me some code guidance on how to proper deal with state and AsyncStorage for TextInput.
I know I have some style issues - would love to fix them, but also comply with SO and keep it on topic.
I removed forceUpdate and replaced FadeImage with just vanilla react native Image.
but I'm still seeing some weird issues

Here is my code
import React from 'react'
import {
StyleSheet,
SafeAreaView,
FlatList,
StatusBar,
ImageBackground,
AsyncStorage,
Platform,
} from 'react-native'
import SplashScreen from 'react-native-splash-screen'
import LinearGradient from 'react-native-linear-gradient'
import { debounce } from 'lodash'
import Section from './Section'
import ButtonContact from './ButtonContact'
import { data } from '../data.json'
export default class App extends React.Component {
constructor(props) {
super(props)
this.state = {
data,
indexRef: data.reduce((result, item, index) => {
result[item.title] = index
return result
}, {}),
ready: false,
}
}
async componentDidMount() {
SplashScreen.hide()
try {
let BusinessPlan = await AsyncStorage.getItem('BusinessPlan')
if (BusinessPlan !== null) {
// We have data!!
let data = JSON.parse(BusinessPlan)
data = this.state.data.map(item => {
const index = data.findIndex(obj => obj.id == item.id)
const pitch = index >= 0 ? data[index].pitch : ''
return { ...item, pitch }
})
this.setState({ data, ready: true })
} else {
this.setState({ ready: true })
}
} catch (error) {
// Error retrieving data
}
}
updatePitch = (id, text) => {
// Copy the data
let data = [...this.state.data]
const index = data.findIndex(obj => obj.id == id)
data[index].pitch = text
// Update the state
this.setState({ data }, this.saveLocally(data))
}
saveLocally = data => {
try {
AsyncStorage.setItem('BusinessPlan', JSON.stringify(data))
} catch (error) {
// Well..
}
}
render() {
return (
<LinearGradient
style={{ flex: 1 }}
start={{ x: 0.0, y: 0.25 }}
end={{ x: 0.5, y: 1.0 }}
colors={['#000000', '#808080', '#000000']}
>
<StatusBar
barStyle={'light-content'}
backgroundColor={Platform.OS == 'iOS' ? 'transparent' : 'black'}
/>
<SafeAreaView>
<ImageBackground
source={require('../images/BackgroundImage.png')}
style={{ width: '100%', height: '100%' }}
resizeMode={'cover'}
>
<FlatList
data={this.state.data}
initialNumToRender="16"
keyExtractor={item => item.id}
renderItem={({ item }) => (
<Section
id={item.id}
title={item.title}
pitch={item.pitch}
updatePitch={debounce(this.updatePitch, 1000)}
questions={item.questions}
ready={this.state.ready}
/>
)}
ListFooterComponent={<ButtonContact />}
style={{
backgroundColor: 'transparent',
borderColor: '#000',
borderWidth: StyleSheet.hairlineWidth,
}}
/>
</ImageBackground>
</SafeAreaView>
</LinearGradient>
)
}
}
const styles = StyleSheet.create({
sectionHeader: {
fontSize: 24,
marginHorizontal: 5,
},
})
(I also updated my git repo)
It seems that the setup I have for state and AsyncStorage works fine with a debounce. The issues I was seeing was because I'm draining the CPU (next step to fix).
I tried your code:
"I'm seeing some strange issues - particularly on the iPhone 8 plus simulator (not seeing the same on iPhone 6 simulator or Android device)" ==> I confirmed this
The app takes about 100% CPU.
After a while trying I figured out:
"I'm seeing some strange issues - particularly on the iPhone 8 plus
simulator (not seeing the same on iPhone 6 simulator or Android
device)" ==> doesn't right, just wait a little TextInput will expand.
There are nothing wrong with state and AsyncStorage. I didn't get any warning.
The root issue is the animation in FadeImage :
The app render many Carousel, and each Carousel has AngleInvestor, and FadeImage. The problem is FadeImage
FadeImage run Animated with duration 1000 => CPU is overloaded
==> That why TextInput add scroll then take a long time to expand, and FlatList look like has problem, but not. They are just slowly updated.
Solution:
Try to comment FadeImage, you will see the problem gone away.
Don't start so many animations as the same time. Just start if it appears (Ex: the first card in Carousel )
UPDATE
I got your problem: typing fastly cause setState call so many times.
You use can debounce for this situation:
In App.js
render() {
console.log('render app.js')
...
<Section
id={item.id}
title={item.title}
pitch={item.pitch}
updatePitch={debounce(this.updatePitch, 1000)} // the key is here
questions={item.questions}
ready={this.state.ready}
/>
You can change the delay and watch the console log to see more. As I tried, delay about 500 can stop the warning.
P/s: You should try to remove forceUpdate
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With