redux 搜索时键入一个符号后,TextInput失去焦点

ruyhziif  于 2022-11-12  发布在  其他
关注(0)|答案(4)|浏览(114)

我有一个平面列表

<View style={styles.container}>
    <FlatList data={this.state.restaurants} 
              renderItem={({ item }) => this.renderItem(item.restaurant)}
              keyExtractor={restaurant => restaurant.key}
              ListHeaderComponent={() => this.renderHeaderComponent()} 
              ItemSeparatorComponent={this.renderSeparator}/>
  </View>

并且在标题中有TextInput我使用TextInput作为搜索栏

renderHeaderComponent() {
    return(
      <View style={{ flexDirection: 'row', marginTop: 10, borderBottomColor: '#CED0CE', borderWidth: 1, borderColor: 'transparent' }}>
        <Icon name='search' size={30} style={{ marginLeft: 10, marginRight: 10 }}/>
        <TextInput
            style={{height: 40, flex: 1}}
            onChangeText={(text) => this.onChangeText(text)}
            placeholder='Type text for search'
            clearButtonMode='while-editing'
            value={this.state.searchText}
      />
      </View>
    );
  };

在onChangeMethod中,我过滤数据。

onChangeText(text) {
    const filteredRestaurants = _.filter(this.props.list, (restaurantObject) => {
      const restaurant = restaurantObject.restaurant;
      const result = restaurant.name.trim().toLowerCase().includes(text.trim().toLowerCase());
      return result;
    })
    this.setState({
      searchText: text,
      restaurants: filteredRestaurants
    });
  }

问题如下。当我在TextInput中键入一个符号时,焦点会立即从TextInput中丢失?如何在键入时保持TextInput中的焦点?

iih3973s

iih3973s1#

为此,您需要使用auto-bound方法,因为ListHeaderComponent的类型是ReactClass,而您当前的方法基本上是在每次数据更新时重新创建并重新绑定它的render,这不是您想要的。
无论如何,对于您的示例,要解决问题,您应该
1)将您的ListHeaderComponent属性更改为
ListHeaderComponent={this.renderListHeader}
2)现在,您希望将renderHeaderComponent方法更改为auto-bound method,这样,每次更改数据(或在'TextInput中输入文本)时,新的呈现器就不会示例化

renderListHeader = () => (
  <View style={{ flexDirection: 'row', marginTop: 10, borderBottomColor: '#CED0CE', borderWidth: 1, borderColor: 'transparent' }}>
      <Icon name='search' size={30} style={{ marginLeft: 10, marginRight: 10 }}/>
      <TextInput
          style={{height: 40, flex: 1}}
          onChangeText={(text) => this.onChangeText(text)}
          placeholder='Type text for search'
          clearButtonMode='while-editing'
          value={this.state.searchText}
      />
  </View>
)
zmeyuzjn

zmeyuzjn2#

从react-native 0.61.5开始,这对于SectionList仍然是一个问题。auto-bound方法不起作用,因为当数据变为空数组时,ListHeaderComponent将重新呈现。
我使用了以下解决方法:
1.将文本输入代码移动到与节列表同级的位置
1.使用“绝对位置”,将其定位在所需的位置。
1.用Animated.View Package
1.利用Animated.event将Y转换为Animated.View
代码示例

const animatedScrollYValue = useRef(new Animated.Value(0)).current;
...
<View>
  <Animated.View style={{
    position: 'absolute',
    top: 142,
    left: 30,
    right: 30,
    zIndex: 1,
    transform: [{ translateY: Animated.multiply(animatedScrollYValue, new Animated.Value(-1)) }] }}>
    // Your text input
  </Animated.View>
  <Animated.SectionList
    scrollEventThrottle={1}
    onScroll={Animated.event([{ nativeEvent: { contentOffset: { y: animatedScrollYValue } } }], { useNativeDriver: true })}
    keyExtractor={(item) => item.id}
    ListHeaderComponent={// Whatever you want but make you include space for the absolute TextInput}
    sections={data}
    renderItem={renderItem}
    renderSectionHeader={renderHeader}
  />
</View>
mfpqipee

mfpqipee3#

我遇到了这个问题,为了解决这个问题,我将renderListHeader Package 在一个React.useMemo钩子中,并将state钩子作为一个项传递给依赖项数组。

renderListHeader = useMemo(() => (
  <View style={{ flexDirection: 'row', marginTop: 10, borderBottomColor: '#CED0CE', borderWidth: 1, borderColor: 'transparent' }}>
      <Icon name='search' size={30} style={{ marginLeft: 10, marginRight: 10 }}/>
      <TextInput
          style={{height: 40, flex: 1}}
          onChangeText={(text) => this.onChangeText(text)}
          placeholder='Type text for search'
          clearButtonMode='while-editing'
          value={this.state.searchText}
      />
  </View>
), [this.onChangeText])
vqlkdk9b

vqlkdk9b4#

我找到了SectionList的另一种解决方法,目前看来还能用,如果我发现它不起作用,我会更新这个答案。我没有在ListHeaderComponent中呈现我的组件,而是在我的数据开始处添加了一个虚拟部分,然后在renderSectionHeader中使用一个条件来呈现它。

<SectionList
  sections={[{ title: 'header', data: [] }, ...sections]}
  renderSectionHeader={({ section }) => 
    section.title === 'header' ? (
      <MyListHeaderComponent />
    ) : (
      <DefaultSectionHeaderComponent />
    )
  }
/>

在Swift/UIKit中使用过一些非常复杂的CollectionView屏幕,这与我们在该环境中处理类似需求的方式没有太大区别,因此希望这意味着引擎盖下的性能不会成为问题,但如果情况如此,我会再次更新这个答案。
另一个选择可能是只是添加一个虚拟项目到您的节数组,使它永远不会成为空的,但我还没有尝试过。

相关问题