react-native-screens: Keyboard doesn't show up when autoFocus on component mount

Hello,

I am trying to use react-native-screens combine with react-navigation for my app for better performance, however I have a weird problem. Indeed, when I have a new page mounting with a TextInput set on autoFocus, it focused as expected but the keyboard does not show up on the screen.

If I don’t put useScreens() it works perfectly, the TextInput is focused and the Keyboard appears.

react-native: 0.59.1; react-navigation: 3.8.1; react-native-screens: 1.0.0-alpha.22; OS: Android; Device: Real;

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 22
  • Comments: 43 (9 by maintainers)

Commits related to this issue

Most upvoted comments

Same problem here.

I’m using a settimeout in componentdidmount to trigger the focus after some milliseconds, but still not the best because there is a necessary delay. setTimeout(() => this.ref.focus(), 150) Remove autoFocus prop on the component or else it won’t work.

Looking forward to a better solution if possible.

Any updates for this problem? I have this problem in Android.

I have tried to use autoFocus and ref, but it didn’t help. What workarounds did you use?

componentDidMount() {
       this.ref.focus();
   }

<TextInput
                           ref={ref => this.ref = ref}
                           autoFocus={true}
                           value={this.props.reflection}
                           onChange={ e => this.props.onChange('reflection', e) }
                       />  

Here it’s working with InteractionManager:

useEffect(() => {
    if (autoFocus  && inputRef.current) {
      if (inputRef.current) {
        InteractionManager.runAfterInteractions(() => {
          inputRef.current?.focus();
        });
      }
    }
  }, [autoFocus, inputRef]);

Had the same issue. react-native-screens upgrading didn’t help.

Solved it by removing autoFocus={true} and setting timeout. I have a popup as a functional component and using “current.focus()” with Refs like this:

const Popup = ({
  placeholder,
  autoFocus,
  showStatus,
}) => {
  const inputRef = useRef(null);
  useEffect(() => {
     Platform.OS === 'ios'
        ? inputRef.current.focus()
        : setTimeout(() => inputRef.current.focus(), 40);
  }, [showStatus]);
  return (
    <View style={styles.inputContainer}>
      <TextInput
        style={styles.inputText}
        defaultValue={placeholder}
        ref={inputRef}
      />
    </View> 
};

400ms only working for me

Platform.OS === “ios” ? this.ref.focus() : setTimeout(() => this.ref.focus(), 400)

For anyone looking for some typescript implementation

const MyTextInput = ({ autoFocus, ...props }: TextInputProps) => {
  const ref = useRef<TextInput>(null);

  useEffect(() => {
    autoFocus &&
      setTimeout(() => {
        if (ref.current) {
          ref.current.focus();
        }
      }, 40);
  });

  return <TextInput ref={ref} {...props} />;
};

I personally am still seeing this issue with 2.0.0-alpha.17 && react-navigation: 4.0.10 on Android devices.

For anyone stumbling on this issue. Here is a reusable TS hook using clind-arthur’s example:

import React from "react";
import { InteractionManager, TextInput } from "react-native";

export default function useAutoFocus(autoFocus = true) {
  const inputRef = React.useRef<TextInput>(null);

  React.useEffect(() => {
    if (autoFocus && inputRef.current) {
      if (inputRef.current) {
        InteractionManager.runAfterInteractions(() => {
          inputRef.current?.focus();
        });
      }
    }
  }, [autoFocus, inputRef]);

  return inputRef;
}

Same problem here.

I’m using a settimeout in componentdidmount to trigger the focus after some milliseconds, but still not the best because there is a necessary delay. setTimeout(() => this.ref.focus(), 150) Remove autoFocus prop on the component or else it won’t work.

Looking forward to a better solution if possible.

I was able to get this to work using a shortened timer (50ms), thank you to the workaround above.

Platform.OS === "ios" ? this.ref.focus() : setTimeout(() => this.ref.focus(), 50)

Bump?

This issue is pretty significant for user experience. I may take care of it later this year if it’s not fixed by then.

const _input = useRef();

  useEffect(() => {
    setTimeout(() => {
      _input.current.input.focus();
    }, 400);
  });

    
<Input
        ref={_input}
        placeholder="Say something about this..."
        inputStyle={style.inputShareStyle}
        inputContainerStyle={{borderBottomWidth: 0}}
        placeholderTextColor="#90949c"
      />

make sure in android you removed autofocus

For anyone stumbling on this issue. Here is a reusable TS hook using clind-arthur’s example:

import React from "react";
import { InteractionManager, TextInput } from "react-native";

export default function useAutoFocus(autoFocus = true) {
  const inputRef = React.useRef<TextInput>(null);

  React.useEffect(() => {
    if (autoFocus && inputRef.current) {
      if (inputRef.current) {
        InteractionManager.runAfterInteractions(() => {
          inputRef.current?.focus();
        });
      }
    }
  }, [autoFocus, inputRef]);

  return inputRef;
}

This works. Why is this issue closed? It’s definitely a significant bug that’s still around.

I solved the problem by showing TextInput only in focused screen. In other words, re-showing TextInput fires auto focus again.

const useNavigationFocus = () => {
  const [isFocused, setIsFocued] = React.useState(true)

  const setFocus = React.useCallback(() => {
    setIsFocued(true)
  }, [])

  const setBlur = React.useCallback(() => {
    setIsFocued(false)
  }, [])

  const navi = useNavigation()

  React.useEffect(() => {
    navi.addListener('focus', setFocus)
    navi.addListener('blur', setBlur)
    return () => {
      navi.removeListener('focus', setFocus)
      navi.removeListener('blur', setBlur)
    }
  }, [])

  return { isFocused }
}

const MyScreen = () => {
  const { isFocused } = useNavigationFocus()
  return (
    <View>
        {isFocused && <TextInput autoFocus />}
    </View>
  )

react-navigation NavigationEvents component seems to also work using the onDidFocus prop, but it feels slower than using the setTimout like above.

<>
        <NavigationEvents onDidFocus={() => this.refs.searchbar.focus()} />
        <Searchbar
          ref="searchbar"
          placeholder="Search"
          onChangeText={this._handleChangeText}
          value={this.state.searchTerms}
        />
</>

Closing since it should be fixed by #1214.

Had the same issue. react-native-screens upgrading didn’t help.

Solved it by removing autoFocus={true} and setting timeout. I have a popup as a functional component and using “current.focus()” with Refs like this:

const Popup = ({
  placeholder,
  autoFocus,
  showStatus,
}) => {
  const inputRef = useRef(null);
  useEffect(() => {
     Platform.OS === 'ios'
        ? inputRef.current.focus()
        : setTimeout(() => inputRef.current.focus(), 40);
  }, [showStatus]);
  return (
    <View style={styles.inputContainer}>
      <TextInput
        style={styles.inputText}
        defaultValue={placeholder}
        ref={inputRef}
      />
    </View> 
};

Also had this problem. I used this and also documentation from here: https://reactnavigation.org/docs/function-after-focusing-screen/

@ferrannp I had the same problem and can confirm that 2.0.0-alpha.3 fixes this issue.

Can you try 2.0.0-alpha3? This https://github.com/kmagiera/react-native-screens/pull/152/files should solve the issue.

Any updates for this problem? I have this problem in Android.

I have tried to use autoFocus and ref, but it didn’t help. What workarounds did you use?

componentDidMount() {
       this.ref.focus();
   }

<TextInput
                           ref={ref => this.ref = ref}
                           autoFocus={true}
                           value={this.props.reflection}
                           onChange={ e => this.props.onChange('reflection', e) }
                       />  

Me too ^^^

any workarounds for this?

My idea is that because it’s creating a new native view it just doesn’t propagate focus event properly on Android. Haven’t researched it properly yet, though.

Yea, it seems this project has quite a few issues compared to plain View-based screens that need to resolved. Everything is more complicated in Native code than in JS.