Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TextInput lost focus after typing one symbol when searching

I have a FlatList

<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>

And have TextInput in header it. I am using TextInput as search bar.

 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>
    );
  };

In onChangeMethod i filter my data.

 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
    });
  }

The problem is following. When I type one symbol in TextInput then focus is lost immediately from TextInput? How can I keep focus in TextInput while typing?

like image 682
Aleksei Danilov Avatar asked Oct 26 '17 07:10

Aleksei Danilov


People also ask

Why does the input field lose focus after typing a character?

When your onChange event fires, the callback calls setState with the new title value, which gets passed to your text field as a prop. At that point, React renders a new component, which is why you lose focus.

How do you keep input focused React?

To set focus on an input field after rendering with React, we can assign a ref to the input element with the useRef hook. Then we call focus on the current value of the ref to focus on the input. to call useRef to create a ref and assign it to inputReference . Then we call inputReference.

What is a React memo?

React. memo is a higher order component. If your component renders the same result given the same props, you can wrap it in a call to React. memo for a performance boost in some cases by memoizing the result. This means that React will skip rendering the component, and reuse the last rendered result.


2 Answers

You need to use an auto-bound method for this, as ListHeaderComponent is of type ReactClass, and your current method basically re-creates and re-binds its render every time the data updates, which is not what you want. This concept is further explained in this comment

Anyway, for your example, to fix your issues you should

1) Change your ListHeaderComponent prop to

ListHeaderComponent={this.renderListHeader}

2) Now you want to change your renderHeaderComponent method to be an auto-bound method, and by doing this a new render will not be instantiated every time you change data ( Or enter text into the `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>
)
like image 91
Ryan Turnbull Avatar answered Nov 14 '22 22:11

Ryan Turnbull


I ran into this, and to solve it I wrapped the renderListHeader in a React.useMemo hook and passed the state hook as an item to the dependency array.

 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])
like image 39
Tomas Gonzalez Avatar answered Nov 14 '22 22:11

Tomas Gonzalez