Last active
August 29, 2020 17:41
-
-
Save david-arteaga/2ea1ea29439e20b1474fa69d821c9376 to your computer and use it in GitHub Desktop.
[React Native Improved TextInput] #react-native #performance #TextInput
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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