Ilja
Ilja

Reputation: 46479

React native TextInput ref error, focus is not a function

I am trying to programatically focus TextInput element with a certain delay after it has mounted, I've got following component (a view that shows input and button)

For some reason this gets error saying

_this2.inputRef.focus is not a function

I'm not sure why. One out of place thing is that I get flow saying that createRef() doesn't exist on React, but I am assuming this is just missing flow definition now, as I am using react 16.3.1 and this was added in 16.3, plus there is no error when its called.

// @flow
import React, { Component, Fragment } from 'react'
import Button from '../../composites/Button'
import TextInput from '../../composites/TextInput'
import OnboardingStore from '../../store/OnboardingStore'
import withStore from '../../store'
import { durationNormal } from '../../services/Animation'

/**
 * Types
 */
export type Props = {
  OnboardingStore: OnboardingStore
}

/**
 * Component
 */
class CharacterNameView extends Component<Props> {
  componentDidMount() {
    this.keyboardTimeout = setTimeout(() => this.inputRef.focus(), durationNormal)
  }

  componentWillUnmount() {
    clearTimeout(this.keyboardTimeout)
  }

  keyboardTimeout: TimeoutID
  inputRef = React.createRef()

  render() {
    const { OnboardingStore } = this.props
    return (
      <Fragment>
        <TextInput
          ref={this.inputRef}
          enablesReturnKeyAutomatically
          value={OnboardingStore.state.username}
          onChangeText={username => OnboardingStore.mutationUsername(username)}
          placeholder="Username"
          blurOnSubmit
          returnKeyType="done"
          onSubmitEditing={/* TODO */ () => null}
        />
        <Button disabled={!OnboardingStore.state.username} color="GREEN" onPress={() => null}>
          Create
        </Button>
      </Fragment>
    )
  }
}

export default withStore(OnboardingStore)(CharacterNameView)

TextInput component I use is imported from this file

// @flow
import React, { Component } from 'react'
import { StyleSheet, TextInput as Input } from 'react-native'
import RatioBgImage from '../components/RatioBgImage'
import { deviceWidth } from '../services/Device'

/**
 * Types
 */
export type Props = {
  style?: any
}

/**
 * Component
 */
class TextInput extends Component<Props> {
  static defaultProps = {
    style: null
  }

  render() {
    const { style, ...props } = this.props
    return (
      <RatioBgImage source={{ uri: 'input_background' }} width={70} ratio={0.1659}>
        <Input
          {...props}
          placeholderTextColor="#4f4a38"
          selectionColor="#797155"
          autoCapitalize="none"
          autoCorrect={false}
          keyboardAppearance="dark"
          style={[styles.input, style]}
        />
      </RatioBgImage>
    )
  }
}

export default TextInput

/**
 * Styles
 */
const styles = StyleSheet.create({
  input: {
    width: '96.4%',
    height: '97.45%',
    color: '#797155',
    fontSize: deviceWidth * 0.043,
    marginLeft: '1%',
    paddingLeft: '5%'
  }
})

Below is what this.innerRef looks like, I don't see any focus property on it at the moment

enter image description here

Upvotes: 2

Views: 4802

Answers (2)

Ilja
Ilja

Reputation: 46479

My issue was in using React.createRef() and assuming I am setting it on a child component. Unfortunately I missed part of the docs about React.forwardRef That I had to use in a child component so ref gets set properly.

Upvotes: 0

Ramon Balthazar
Ramon Balthazar

Reputation: 4260

inputRef is a property of the class instance, set it inside a class method.

Using a constructor, for instance:

class CharacterNameView extends Component<Props> {
  constructor() {
    this.inputRef = React.createRef()
  }
  ...
}

Upvotes: 1

Related Questions