n80
n80

Reputation: 175

React Native TextInput loses focus in JSX component

When I move a TextInput into a custom JSX component it loses focus as soon as I modify the text.

In the example below a near identical TextInput is also created in render() without using a component tag and it does not lose focus.

I have read about the key attribute and how focus can be lost if this is not specified or not unique. However, in the simple example below key attributes are unique.

import React, { Component } from 'react'
import {
  AppRegistry,
  Text,
  View,
  TextInput,
} from 'react-native'

class App extends Component {

    constructor(props) {
      super(props);

      this.state = { 
          text: "111"          
      };

    }

  render() {

    var t = this;

    function Dynamic(props) {

      var text = props.text;

      return  <TextInput key="textinput1" style={{width:"100%", padding:10, 
            borderWidth:1, marginTop:20, marginBottom:20}}
            onChangeText={(text) => { t.setState({text}) } }                                
            value={text}
            />

    }

    return (
      <View >        
        <Text>DYNAMIC COMPOMENT - LOSES FOCUS</Text>        
        <Dynamic key="dynamickey" text={this.state.text}></Dynamic>         

        <Text>NOT DYNAMIC - KEEPS FOCUS</Text>
        <TextInput key="textinput2" style={{width:"100%", padding:10, 
            borderWidth:1, marginTop:20, marginBottom:20}}
            onChangeText={(text) => { t.setState({text}) } }                             
            value={this.state.text}
            />                
      </View>
    )
 }
}

AppRegistry.registerComponent('App', () => App)

Any input on what is happening here or how to deal with it would be very much appreciated.

Upvotes: 7

Views: 10848

Answers (1)

marizikmund
marizikmund

Reputation: 408

It looks like the problem is that you're defining your Dynamic inside it's parent render method and then calling the parent's setState method directly (instead of passing through props), which causes rerender that you don't want. Try it like this:

import React, { Component } from "react";
import { AppRegistry, Text, View, TextInput } from "react-native";

class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
      text: "111"
    };
  }

  render() {
    var t = this;

    return (
      <View>
        <Text>DYNAMIC COMPOMENT - LOSES FOCUS</Text>
        <Dynamic
          key="dynamickey"
          text={this.state.text}
          changeText={text => this.setState({ text })}
        />

        <Text>NOT DYNAMIC - KEEPS FOCUS</Text>
        <TextInput
          key="textinput2"
          style={{
            width: "100%",
            padding: 10,
            borderWidth: 1,
            marginTop: 20,
            marginBottom: 20
          }}
          onChangeText={text => {
            t.setState({ text });
          }}
          value={this.state.text}
        />
      </View>
    );
  }
}
const Dynamic = ({ text, changeText }) => {
  return (
    <TextInput
      key="textinput1"
      style={{
        width: "100%",
        padding: 10,
        borderWidth: 1,
        marginTop: 20,
        marginBottom: 20
      }}
      onChangeText={changeText}
      value={text}
    />
  );
};

AppRegistry.registerComponent("App", () => App);

Here is a working sample: https://snack.expo.io/BJ-SARfdM

Upvotes: 10

Related Questions