1

Instead of re-rendering the entire component-tree whenever "<InputText style{...}>" is changed, I am trying to use refs in my Class Component. (I am using React Native with Expo managed workflow.)

Using refs, the typed text appears as it should in the InputText field. But, when a button is pressed, the value of the typed text (value of the InputText) should be console logged, however it is not.

export class Feed extends Component {
constructor(props){    
  super(props);
  this.state = {
    //some state variables
  }
  this.myTextFromInput = React.createRef()
}

I started by creating the myTextFromInput ref (above).

<TextInput 
style={{height:100}}  
ref={this.alias} 
placeholder="Input Text Here"
/>

I then used the myTextFromInput ref in the InputText component. And lastly, the button!

<Button onPress={()=>console.log(this.myTextFromInput.current.value)}>Press me!</Button>

This gives me undefined. I have also tried this.myTextFromInput.value and a .getText() method which is outdated.

How can I obtain the inputed text?

UPDATE: Terminal log undefined. But snack works fine!?

enter image description here

  • You are passing `this.alias` to `TextInput` while you defined the ref as `this.myTextFromInput`, aren't you? – David Scholz May 02 '22 at 18:52
  • Oops yes! My bad I changed the ref name for this stackoverflow post. Ref was all 'alias' before. It did't work. So changing to myText... is not the full solution. – William O'Brien May 02 '22 at 19:22

1 Answers1

1

You aren't passing the correct reference to TextInput, it should be this.myTextFromInput not this.alias, take a look:

export class Feed extends Component {
  constructor(props){    
    super(props);
    this.state = {
      //some state variables
    }
    this.myTextFromInput = React.createRef()
    // bind the method to the component instance
    this.logInputText = this.logInputText.bind(this)
  }
 
  logInputText() {
    console.log(this.myTextFromInput.current.value)
  }
  
  render() {
    return (
      <View>
        <TextInput 
          style={{height:100}}
          // pass the correct reference here  
          ref={this.myTextFromInput} 
          placeholder="Input Text Here"
        />
        <Button 
         onPress={this.logInputText}>
         Press me! 
        </Button>
      </View>
    )
  }
}

Also don't forget that whether you use a method instead of arrow function you've to bind it to the class instance, like I did. See this question and this example from react docs.

Update: React.ref on Android and iOS doesn't seems to work as the same way as it works on web, you can't get the value from input because the component doesn't provide this property, doing a console.log(this.myTextFromInput.current) you can see all the available properties. One solution from this question is to use TextInput from the package react-native-paper, as it provides the input value from the ref, or you could use the common state approach to store the input value, like so:

export class Feed extends Component {
  constructor(props){    
    super(props);
    this.state = {
      myTextFromInput: ""
    }
    // bind the method to the component instance
    this.logInputText = this.logInputText.bind(this)
  }
 
  logInputText() {
    console.log(this.state.myTextFromInput)
  }
  
  render() {
    return (
      <View>
        <TextInput 
          style={{height:100}}
          // you don't need to use ref
          placeholder="Input Text Here"
          onChangeText={(text) => this.setState({myTextFromInput: text})}
        />
        <Button 
         onPress={this.logInputText}>
         Press me! 
        </Button>
      </View>
    )
  }
}
Yago Biermann
  • 1,494
  • 1
  • 7
  • 20
  • Thank you for this answer! I think it could work but I got logInputText is not defined. `this.logInputText = logInputText.bind(this)` referring to the logInputText right of the equal sign. I tried put this. in front but the log just returned `ƒ logInputText() { console.log(this.alias.current.value); } ` – William O'Brien May 02 '22 at 19:19
  • Any suggestions on what I could at this point? Thanks! – William O'Brien May 02 '22 at 20:25
  • Did you implement your code just like my answer? Note that the onPress listener should be like that: `onPress={this.logInputText}`, **NOT** like this `onPress={() => this.logInputText}` – Yago Biermann May 02 '22 at 20:32
  • Yes, I did just like your answer. Please see https://snack.expo.dev/@bilbam04/refs-stackoverflow. Still not working... Could you edit a snack maybe so we can see it works there? – William O'Brien May 03 '22 at 09:16
  • It was my mistake, I'm sorry about that. On constructor where I'm binding to this change as follow: `this.logInputText = this.logInputText.bind(this)`, see the [working example](https://snack.expo.dev/@yagobiermann/refs-stackoverflow). – Yago Biermann May 03 '22 at 13:55
  • No worries, so the snack works now! Thank you! But the weird thing is that it doesn't work in my actual project. I literally just copy and paste the whole snack - still give me `undefined`. See terminal log in question (I will update it with a screen shot). I was thinking it might be due to my RN version. What version are you using? Or do could it be something else? – William O'Brien May 03 '22 at 15:39
  • 1
    After some research I could figure it out, unfortunately the react.ref on Android and iOS doesn't seems to work as the same way as it works on web, you can't get the value from input because it doesn't provide this property, doing a `console.log(this.myTextFromInput.current)` you can see all the properties from the component. See [this answer](https://stackoverflow.com/a/61952283/12898748), a possible solution is to use the **react-native-paper** package or go with the common approach of using the **react state** to store the value from input. – Yago Biermann May 03 '22 at 16:50