问题:React-Native-键盘在TextInput的每次击键时关闭

时间:2020-05-09 17:12:36

标签: reactjs react-native keyboard array.prototype.map

针对此问题的完整免责声明-我已经与React Native进行了大约一两个星期的合作,并且我怀疑我在未完全理解原因的情况下遇到了此问题!

问题:在TextInput字段中的每个击键上,键盘都会自动关闭,并且仅记录第一个击键。

情况:我使用预先定义的数组作为useState的默认值。根据当前状态,使用.map()调用TextInput字段。 onChangeText()更新状态以捕获对数组的更改。每次击键都会更新状态。

尝试过的事情:

  1. 向/ map()中使用的不同组件添加/删除密钥
  2. 在调用.map()的ScrollView中添加keyboardShouldPersistTaps ='handled',包括所有可用的其他变体

是否有人知道导致每次击键时键盘关闭的原因,以及如何在继续捕获主要状态下TextInput字段的更改的同时防止这种情况的发生?

我正在处理的代码下面的代码片段(我删除了一些不相关的细节):

import React, { useState } from 'react';
import {
  View,
  Text,
  Button,
  TextInput,
  SectionList,
  SafeAreaView,
  TouchableOpacity,
  ScrollView,
  Modal,
} from 'react-native';
import { Picker} from '@react-native-community/picker';



//import custom components

import { styles, Break } from './MasterStyles';
import { inputData, ingredients } from './inputData';



function addNewLoaf() {

  const [ingredientsList, setIngredientsList] = useState(ingredients);
  const [selectedLoaf, setSelectedLoaf] = useState('Regular Loaf');
  const [flourModalVisibility, setFlourModalVisibility] = useState(false);
  const [newLoaf, setNewLoaf] = useState('');

  function IngredientsRecorder() {

    return (
      <View style={styles.ingredientsContainer}>
        <View style={{flexDirection: 'column'}}>
          <View>
            <Text style={styles.metricTitle}>
              Volume of Ingredients:
            </Text>
          </View>
          {
            ingredientsList.map(e => {
              if(e.isVisible && e.ingredient){
                return (
                  <View style={{flexDirection: 'row', alignItems: 'center'}} key={e.id}>
                    <View style={{flex:2}}>
                      <Text style={styles.metricText}>{e.name}:</Text>
                    </View>
                    <View style={{flex:3}}>
                      <TextInput
                        placeholder='amount'
                        style={styles.inputText}
                        keyboardType='number-pad'
                        value={e.amount}
                        onChangeText={value => ingredientsAmountHandler(value, e.id)}
                      />
                    </View>
                    <View style={{flex:1}}>
                      <Text style={styles.ingredientsText}>{e.units}</Text>
                    </View>
                  </View>
                )
              }
            })
          }
        </View>
      </View>
    )
  }



  const ingredientsAmountHandler = (text, id) => {
    // setAmount(enteredText);

    let newArray = [...ingredientsList]
    let index = newArray.findIndex(element => element.id === id)

    newArray[index].amount = text
    setIngredientsList(newArray)
  }


  return (
    <SafeAreaView style={styles.container}>
      <View style={styles.page}>
        <Text style={styles.titleText}>Add a New Loaf</Text>
        <Break />
        <View style={{flexDirection: 'row'}}>
          <TextInput 
            placeholder='What would you like to call your loaf?' 
            style={styles.inputText}
            onChangeText={loafNameInputHandler}
            value={newLoaf}
          />
          <Button title='Create Loaf' color='#342e29' onPress={addNewLoafHandler} />
        </View>
        <Break />
        <ScrollView styles={styles.page} keyboardShouldPersistTaps='handled'>
          <LoafSelector />
          <FlourSelector />
          <IngredientsRecorder />
        </ScrollView>
      </View>
      <Break />
    </SafeAreaView>
  );
}

  export { addNewLoaf }

3 个答案:

答案 0 :(得分:3)

由于您正在更改列表,因此所有输入都将重新呈现。避免这种情况的一种方法是将当前的编辑文本存储到另一个状态值中,并在提交输入或失去焦点后将其合并到列表中。这是最小的示例:

let defaultTemp={editingIndex:-1,text:''}

let [temp,setTemp] = useState(defaultTemp); //We will store current being edited input's data and index

{
        ingredientsList.map((e,i) => {
          if(e.isVisible && e.ingredient){
            return (
              <View style={{flexDirection: 'row', alignItems: 'center'}} key={e.id}>
                <View style={{flex:2}}>
                  <Text style={styles.metricText}>{e.name}:</Text>
                </View>
                <View style={{flex:3}}>
                  <TextInput
                    placeholder='amount'
                    style={styles.inputText}
                    keyboardType='number-pad'
                    value={temp.editingIndex===i?temp.text:e.amount}
                    //the input got focus
                    onFocus={()=>setTemp({editingIndex:i,text:e.amount})}
                    //the input lost focus
                    onBlur={()=>{
                         ingredientsAmountHandler(temp.text, e.id)
                         setTemp(defaultTemp)
                    }
                    onChangeText={text => setTemp({text,editingIndex:i})}
                  />
                </View>
                <View style={{flex:1}}>
                  <Text style={styles.ingredientsText}>{e.units}</Text>
                </View>
              </View>
            )
          }
        })
      }

答案 1 :(得分:0)

这里的主要问题是键盘关闭,这里有一个简单的解决方案。将属性 autoFocus={true} 添加到您的 TextInput。每当页面刷新或其他任何时候,这将自动关注输入字段。

答案 2 :(得分:0)

对此的一种解决方案是在 Input 上使用 onEndEditing 道具。您可以使用带有 onChange 道具的本地状态,然后一旦用户点击离开/点击完成,就会调用 onEndEditing 函数,您可以将本地状态应用到父状态。


 const TextInput = ({ value, onChange }) => {
      const [currentValue, setCurrentValue] = useState(`${value}`);
      return (
          <Input
            value={currentValue}
            onChangeText={v => setCurrentValue(v)}
            onEndEditing={() => onChange(currentValue)}
          />
      );
 };

这样父 onChange 属性只会在字段更新完成后才被调用,而不是在每次击键时调用。除非您正在做一些奇特的事情,否则这很好用。