React Get state of native elemet

I am making my custom components that wrap react-native components. I am currently making MyInput component. It uses TextInput component.I want to know state of TextInput component, but i dont want to use onFocus or onBlur etc. I am trying to pass all of those props trough. I am currently trying with using refs, but it is not working properly because there is delay. "isFocused" only turns true when I start typing, not on click. Is there some good way to solve this?

interface InputProps extends TextInputProps {
}
export const Input = ({
  children,
  ...props
}: PropsWithChildren<InputProps>) => {
  const { themeStyles } = useContext(ThemeContext);
  const { styles } = useStyles(themeStyles);
  const inputRef = useRef<TextInput>(null);
  const isFocused = inputRef.current?.isFocused(); // not working properly
  return (
    <View style={[styles.inputContainer]}>
      <TextInput ref={inputRef} {...props} style={[styles.input, isFocused && styles.blueText]}>
        {children}
      </TextInput>
    </View>
  );
};

>Solution :

To be honest with you, I don’t see a good way of doing this without using onFocus and onBlur. Your isFocused variable is only updating when your component re-renders, which is why you’re seeing the behavior you don’t like.

You could try this, but I’m not sure that it’s ideal or will generate the desired results:

export const Input = ({
  children,
  ...props
}: PropsWithChildren<InputProps>) => {
  const { themeStyles } = useContext(ThemeContext);
  const { styles } = useStyles(themeStyles);
  const inputRef = useRef<TextInput>(null);
  // const isFocused = inputRef.current?.isFocused(); // not working properly

  return (
    <View style={[styles.inputContainer]}>
      <TextInput ref={inputRef} {...props} style={[styles.input, inputRef.current?.isFocused() && styles.blueText]}>
        {children}
      </TextInput>
    </View>
  );
};

I don’t know what your restrictions are, but based on your description, I might try merging the onFocus and onBlur props passed to Input with internal functions that set the desired styles. Something like this:

export const Input = ({
  children,
  onFocus,
  onBlur,
  ...props
}: PropsWithChildren<InputProps>) => {
  const { themeStyles } = useContext(ThemeContext);
  const { styles } = useStyles(themeStyles);
  const inputRef = useRef<TextInput>(null);

  const [focusedStyle, setFocusedStyle] = useState(undefined);
  
  const onInputFocus = useCallback((e) => {
    onFocus(e);
    setFocusedStyle(styles.blueText);
  }, [onFocus]);
  const onInputBlur = useCallback((e) => {
    onBlur(e);
    setFocusedStyle(undefined);
  }, [onBlur]);

  return (
    <View style={[styles.inputContainer]}>
      <TextInput ref={inputRef} {...props} style={[styles.input, focusedStyle]} onFocus={onInputFocus} onBlur={onInputBlur}>
        {children}
      </TextInput>
    </View>
  );
};

Alternatively, have you considered using a library like React Native Paper? It’s TextInput component handles this for you, and exposes props for both focused/unfocused styling.

Leave a Reply