简体   繁体   English

React Native:TextInput with state和AsyncStorage

[英]React Native: TextInput with state and AsyncStorage

When typing on the keyboard I was seeing some warnings about the input being ahead of the JS code.. 在键盘上键入时,我看到一些关于输入的警告在JS代码之前。

Native TextInput(react native is awesome) is 4 events ahead of JS - try to make your JS faster. 原生TextInput(本机反应很棒)是JS之前的4个事件 - 尝试让你的JS更快。

So added the debounce and got this to "work": 所以添加了debouncedebounce “工作”:

...
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) 顺便说一句:我现在正在做一些“道具钻探” - 但计划使用Context API(做出反应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) 警告似乎已经通过添加debounce (1)而消失了。但我看到了一些奇怪的问题 - 特别是在iPhone 8 plus模拟器上(在iPhone 6模拟器或Android设备上看不到相同)

Issues observed: 发现的问题:

  • TextInput don't expand - it just add scolling (expands on iPhone 6 and Android device) TextInput不会扩展 - 只需添加scolling(在iPhone 6和Android设备上展开)
  • Some layout issues in the FlatList - seems like it has problems finding correct height of list elements.. FlatList中的一些布局问题 - 似乎在查找列表元素的正确高度时遇到了问题。

What is the best practice for fast JS code and saving to both state and AsyncStorage ? 快速JS代码和保存到stateAsyncStorage的最佳实践是什么?

(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. (1)的另一种方式比使用debounce可以使用getDerivedStateFromProps和添加某种计时器的一段时间后推的状态到母部件的..但不能肯定,这将让JS代码更快。 So didn't try it. 所以没试过。

UPDATE (again) 更新(再次)

开源

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. 我开源了整个代码,因为当代码嵌套时很难在SO帖子中提供所有需要的信息。

The entire code is here: https://github.com/Norfeldt/LionFood_FrontEnd 整个代码在这里: 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 . 我不希望人们进入并使用PR修复我的代码(即使它会很棒),但只是给我一些关于如何正确处理stateTextInput AsyncStorage代码指导。

I know I have some style issues - would love to fix them, but also comply with SO and keep it on topic. 我知道我有一些风格问题 - 很想修复它们,但也要遵守SO并保持主题。

Update II 更新II

I removed forceUpdate and replaced FadeImage with just vanilla react native Image . 我删除了forceUpdate并用vanilla react本机Image替换了FadeImage

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) (我也更新了我的git repo)

Update III 更新III

It seems that the setup I have for state and AsyncStorage works fine with a debounce . 似乎我对stateAsyncStorage的设置在debounce工作正常。 The issues I was seeing was because I'm draining the CPU (next step to fix). 我看到的问题是因为我正在耗尽CPU(下一步要修复)。

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 “我看到一些奇怪的问题 - 特别是在iPhone 8 plus模拟器上(在iPhone 6模拟器或Android设备上没有看到相同的内容)”==>我证实了这一点

  • The app takes about 100% CPU. 该应用程序需要大约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. “我看到一些奇怪的问题 - 特别是在iPhone 8 plus模拟器上(在iPhone 6模拟器或Android设备上没有看到相同的内容)”==>不对,只需等待一点TextInput就会扩展。

  • There are nothing wrong with state and AsyncStorage. state和AsyncStorage没有任何问题。 I didn't get any warning. 我没有得到任何警告。

The root issue is the animation in FadeImage : 根问题是FadeImage的动画:

  • The app render many Carousel , and each Carousel has AngleInvestor , and FadeImage . 该应用程序渲染许多Carousel ,每个Carousel都有AngleInvestorFadeImage The problem is FadeImage 问题是FadeImage

  • FadeImage run Animated with duration 1000 => CPU is overloaded FadeImage运行Animated ,持续时间为1000 => CPU过载

    ==> That why TextInput add scroll then take a long time to expand, and FlatList look like has problem, but not. ==>为什么TextInput添加滚动然后需要很长时间才能展开,而FlatList看起来有问题,但不是。 They are just slowly updated. 他们只是慢慢更新。

Solution: 解:

  • Try to comment FadeImage , you will see the problem gone away. 尝试评论FadeImage ,你会发现问题消失了。

  • Don't start so many animations as the same time. 不要同时启动这么多动画。 Just start if it appears (Ex: the first card in Carousel ) 如果它出现就开始(例如: Carousel的第一张卡片)

UPDATE UPDATE

I got your problem: typing fastly cause setState call so many times . 我遇到了你的问题: 快速输入会导致setState调用很多次 You use can debounce for this situation: 你使用可以debounce这种情况:

In App.js 在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. 我试过,延迟大约500可以停止警告。

P/s: You should try to remove forceUpdate P / s:您应该尝试删除forceUpdate

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM