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

Jam*_*e T 5 keyboard reactjs react-native array.prototype.map

这个问题的完整免责声明 - 我已经使用 react native 工作了大约一两个星期,我怀疑我在没有完全理解原因的情况下遇到了这个问题!

问题:在 TextInput 字段中的每次击键时,键盘会自动关闭并且只记录第一次击键。

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

尝试的事情:

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

有谁知道是什么导致键盘在每次击键时关闭,以及如何在继续捕获主状态中 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 }
Run Code Online (Sandbox Code Playgroud)

Dav*_*nes 6

解决此问题的一种方法是使用输入上的 onEndEditing 属性。您可以将本地状态与 onChange 属性一起使用,然后一旦用户单击离开/单击完成,就会调用 onEndEditing 函数,您可以将本地状态应用于父状态。


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

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


Ori*_*ero 5

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

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