Skip to content

Instantly share code, notes, and snippets.

@david-arteaga
Last active August 29, 2020 17:41
Show Gist options
  • Save david-arteaga/2ea1ea29439e20b1474fa69d821c9376 to your computer and use it in GitHub Desktop.
Save david-arteaga/2ea1ea29439e20b1474fa69d821c9376 to your computer and use it in GitHub Desktop.
[React Native Improved TextInput] #react-native #performance #TextInput
import React, {useCallback, useRef, useLayoutEffect} from 'react';
import {TextInput as RNTextInput, TextInputProps} from 'react-native';
const TextInput = React.forwardRef<RNTextInput, TextInputProps>(
function TextInput(
{value, onChangeText: _onChangeText, defaultValue: _defaultValue, ...props},
forwardRef,
) {
const ref = useRef<RNTextInput | null>(null);
// Default value will only get calculated on first render.
// Constantly changing the value of the "defaultValue" value prop also causes performance issues
const defaultValue = useRef(value ?? _defaultValue ?? undefined).current;
// Used to keep track of the inner TextInput text value
const inputValueRef = useRef(defaultValue);
const onChangeText = useCallback(
(v) => {
inputValueRef.current = v;
_onChangeText?.(v);
},
[inputValueRef, _onChangeText],
);
// This will set imperatively set the input text if the "value" gets set to another value
// from the parent controlling component
// This part is allows this component to still be "controlled" even though it is actually not
useLayoutEffect(() => {
const isInputValueDifferent = value !== inputValueRef.current;
if (isInputValueDifferent) {
ref.current?.setNativeProps({text: value});
inputValueRef.current = value;
}
}, [value]);
const refCallback = useCallback(
(instance: RNTextInput | null): void => {
ref.current = instance;
setRef(forwardRef, instance);
},
[forwardRef],
);
return (
<RNTextInput
ref={refCallback}
{...props}
defaultValue={defaultValue}
onChangeText={onChangeText}
/>
);
},
);
export default TextInput;
function setRef(
forwardRef:
| ((instance: RNTextInput | null) => void)
| React.MutableRefObject<RNTextInput | null>
| null,
instance: RNTextInput | null,
) {
if (forwardRef) {
if (typeof forwardRef === 'function') {
forwardRef(instance);
} else {
forwardRef.current = instance;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment