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.