javascriptreactjsreact-nativeexpotextinput

React Native TextInput ReRenders when calling useState Hook inside a custom component


Description When a TextInput component triggers action such as in onChangeText or onKeyPress method which then triggers setState, the component will re render and lose focuse.

React Native version: 0.62 (Unable to upgrade due to use of Expo)

Steps To Reproduce Provide a detailed list of steps that reproduce the issue.

  1. Create a Custom Wrapper Component simple like
  2. Declare useStateHook
  3. Pass TextInput to the Wrapper Component either by direct JSX or Custom Component
  4. Bind setState function to any of event listeners of TextInput.

Expected Results sets State but does not lose focus or rerenders

Snack, code example, screenshot, or link to a repository: Expo Example https://snack.expo.io/@ksi9302/1f9369

Hi Guys, this is a bug report I made to React Native. But I'm not sure if I'm doing something wrong here.

What I've tried so far and doesn't work

  1. Get rid of all styles.
  2. make custom input component with class react component, disable shouldComponentUpdate
  3. not binding value
  4. make different state structure and actually pass within object {}
  5. make dummy key

What I know will work

Bad Compromise


Solution

  • Take the wrapper out as it keeps getting rerendered due to the search value changes.

    import React, { useState } from "react";
    import { View, TextInput } from "react-native";
    
    const Test = () => {
      const handleChange = e => {
        setSearch(e);
      };
      const [search, setSearch] = useState(null);
    
      return (
        <Wrapper>
          <TextInput
            value={search}
            onChangeText={e => {
              handleChange(e);
            }}
            placeholder="type here"
          />
        </Wrapper>
      );
    };
    
    const Wrapper = props => {
        return (
          <View
            style={{
              width: "100%",
              height: "100%",
              alignItems: "center",
              justifyContent: "center",
              display: "flex",
            }}
          >
            {props.children}
          </View>
        );
      };
    
    export default Test;