React Native:TextInput with state和AsyncStorage

Nor*_*ldt 11 javascript android ios reactjs react-native

在键盘上键入时,我看到一些关于输入的警告在JS代码之前.

原生TextInput(本机反应很棒)是JS之前的4个事件 - 尝试让你的JS更快.

所以添加了debounce并使其"工作":

...
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() {
  ...
Run Code Online (Sandbox Code Playgroud)

顺便说一句:我现在正在做一些"道具钻探" - 但计划使用Context API(做出反应16.3)

警告似乎已经添加debounce(1)..但我看到一些奇怪的问题 - 特别是在iPhone 8 plus模拟器上(在iPhone 6模拟器或Android设备上看不到相同)

发现的问题:

  • TextInput 不要扩展 - 它只是添加scolling(在iPhone 6和Android设备上扩展)
  • - 中的一些布局问题FlatList- 似乎在查找列表元素的正确高度时遇到了问题.

什么是快速JS代码,并保存到两个最佳实践stateAsyncStorage

(1)另一种方法debounce可能是使用getDerivedStateFromProps并添加某种计时器,在一段时间后将状态推送到父组件.但是不确定这会使JS代码更快.所以没试过.

更新(再次)

开源

我开源了整个代码,因为当代码嵌套时很难在SO帖子中提供所有需要的信息.

整个代码在这里:https: //github.com/Norfeldt/LionFood_FrontEnd

(我知道我的代码可能看起来很乱,但我还在学习..)

我不希望人们去和修复我的代码以PR(尽管这将是真棒),但只要给我上如何正确处理一些代码的指导state,并AsyncStorageTextInput.

我知道我有一些风格问题 - 很想修复它们,但也要遵守SO并保持主题.

更新II

我删除forceUpdate并替换FadeImage为香草反应原生Image.

但我仍然看到一些奇怪的问题

奇怪的行为

这是我的代码

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,
  },
})
Run Code Online (Sandbox Code Playgroud)

(我也更新了我的git repo)

更新III

似乎我的设置stateAsyncStorage工作正常debounce.我看到的问题是因为我正在耗尽CPU(下一步要修复).

tul*_*dev 3

我尝试了你的代码:

  • “我看到一些奇怪的问题 - 特别是在 iPhone 8 plus 模拟器上(在 iPhone 6 模拟器或 Android 设备上没有看到相同的问题)”==> 我确认了这一点

  • 该应用程序占用大约 100% 的 CPU。

经过一段时间的尝试我发现:

  • “我看到一些奇怪的问题 - 特别是在 iPhone 8 plus 模拟器上(在 iPhone 6 模拟器或 Android 设备上没有看到相同的问题)” ==> 不对,稍等一下TextInput就会扩大。

  • state 和 AsyncStorage 没有任何问题。我没有收到任何警告。

根本问题是动画FadeImage

  • 该应用程序渲染了很多Carousel,并且每个Carousel都有AngleInvestor, 和FadeImage。问题是FadeImage

  • FadeImage运行Animated持续时间 1000 => CPU 过载

    ==> 这就是为什么TextInput添加滚动然后需要很长时间才能展开,FlatList看起来有问题,但事实并非如此。它们只是慢慢更新。

解决方案:

  • 尝试发表评论FadeImage,你会发现问题消失了。

  • 不要同时启动这么多动画。如果出现就开始(例如:中的第一张牌Carousel

更新

我遇到了您的问题:打字速度太快导致setState呼叫次数太多debounce对于这种情况,您可以使用:

在 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}
                />
Run Code Online (Sandbox Code Playgroud)

您可以更改延迟并观看控制台日志以了解更多信息。正如我所尝试的,延迟大约 500 可以停止警告。

P/s:你应该尝试删除forceUpdate