Peter
Peter

Reputation: 45

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

Upvotes: 3

Views: 4292

Answers (3)

Muhammad Farhan
Muhammad Farhan

Reputation: 117

If you really want to keep your wrapper inside the test component and do not want keyboard to close, the one approach could be to use useCallback to memoize your wrapper (below is the working code of your example with useCallback).

import React, {useState, useCallback} from 'react';
import {View, TextInput, Text} from 'react-native';

const Test = () => {
  const [search, setSearch] = useState(''); 

  const Wrapper = useCallback(props => {
    return (
      <View
        style={{
          width: '100%',
          height: '100%',
          alignItems: 'center',
          justifyContent: 'center',
          display: 'flex',
          backgroundColor: 'pink',
        }}>
        {props.children}
      </View>
    );
  }, []); 
  

  return (
    <Wrapper>
      <TextInput
        value={search}
        style={{backgroundColor: 'white', width: 200, height: 40}}
        onChangeText={setSearch} 
        placeholder="type here"
      />
      <Text>{search}</Text>
    </Wrapper>
  );
};

export default Test;

Upvotes: 0

Dilettante258
Dilettante258

Reputation: 1

I also encountered this problem, but later I solved it using useMemo hook. After doing this, my keyboard will no longer lose focus. I left this comment to help people who have encountered the same problem as me.

Upvotes: 0

D10S
D10S

Reputation: 1549

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;

Upvotes: 3

Related Questions