I'm trying to dynamically apply margin & padding to a View, based on a ref'd TextInput's borderRadius. I am new to React coming from Xamarin where this type of thing is common.
I'm not sure if I have the correct approach, but I have seen some examples of people deriving style values from useRef.
Here is my custom LabelInput component:
import React, {useState} from 'react';
import {
View,
Animated,
StyleSheet,
ViewProps,
} from 'react-native';
import {Colors} from '../../../resources/colors';
import Text from './Text';
import TextInput from './TextInput';
import {TextInputProps} from 'react-native/Libraries/Components/TextInput/TextInput';
import {isNullOrWhiteSpace} from '../../../utils/stringMethods';
import {TextProps} from 'react-native/Libraries/Text/Text';
interface LabeledInputProps {
label: string;
error: string;
onChangeText: (text: string) => void;
placeholder?: string;
inputValue: string;
mask?: (text: string) => string;
validator?: (text: string) => string;
onValidate?: (value: string) => void;
viewProps?: ViewProps;
textProps?: TextProps;
errorTextProps?: TextProps;
inputProps?: TextInputProps;
}
export default function LabeledInput(props: LabeledInputProps) {
const inputRef = React.useRef<any>(null);
const [dynamicStyle, setDynamicStyle] = useState(StyleSheet.create({
dynamicContainer:{
marginHorizonal: 0,
paddingHorizonal: 0,
}
}));
const changeTextHandler = (inputText: string) => {
const displayText = props?.mask ? props.mask(inputText) : inputText;
props.onChangeText(displayText);
// ultimately not the exact behavior I'm after, but this is a simple example.
var test = inputRef.current.props.style;
// props.style always returns undefined,
// there doesn't appear to be a 'props' property on the 'current' object when debugging.
setDynamicStyle(StyleSheet.create({
dynamicContainer:{
marginHorizonal: test.borderRadius, // I want the padding/margin of this element to be
paddingHorizonal: test.borderRadius,// dynamically set based on the inputRef's borderRadius
}
}))
};
return (
<View
{...props.viewProps}
style={[
props.viewProps?.style,
localStyles.container,
]}>
<TextInput
ref={inputRef}
{...props.inputProps}
placeholder={props.placeholder}
style={localStyles.input}
onChangeText={changeTextHandler}
value={props.inputValue}
/>
<Animated.View
pointerEvents={'none'}>
<Text
{...props.textProps}
style={[props.textProps?.style, animatedStyles.label]}>
{props.label}
</Text>
</Animated.View>
{/* {stuff} */}
</View>
);
}
const localStyles = StyleSheet.create({
container: {
backgroundColor: 'blue',
justifyContent: 'flex-start',
flex: 1,
},
label: {
fontWeight: 'bold',
marginBottom: 8,
},
input: {
padding: 8,
},
error: {
backgroundColor: 'pink',
fontSize: 12,
paddingHorizontal: 8,
color: Colors.danger,
marginTop: 4,
},
});
const animatedStyles = StyleSheet.create({
label: {
fontSize: 16,
fontWeight: 'normal',
},
});
Here is my custom LabelInput component with forwardRef() implemented:
import React, {ForwardedRef, forwardRef} from 'react';
import {TextInput as NativeTextInput, TextInputProps} from 'react-native';
import {useGlobalStyles} from '../../../resources/styles';
const TextInput = (
props: TextInputProps,
ref: ForwardedRef<NativeTextInput>,
) => {
const styles = useGlobalStyles();
return (
<NativeTextInput
{...props}
ref={ref}
style={[styles.textInput, props.style]}
placeholderTextColor={styles.textInput.borderColor}
onChangeText={(text: string) => {
if (props.onChangeText) {
props.onChangeText(text);
}
}}
/>
);
};
export default forwardRef(TextInput);
I've tried referencing inputRef from different hooks, like useCallback & useEffect.
var test = inputRef.current.props.style; always returns undefined. And there doesn't appear to be a 'props' property on the 'current' object when debugging.
The link you mentioned contains two files with
inputRef. SinceinputRefis in parent component and userefprop to pass inputRef, this will not work.refis not available as prop. If you still want to use ref as prop, then use forward ref in child component as access the ref as second argument or you can use any other prop name to pass ref i.e.innerRef. You can read more in react documentation. Forward RefsAccording to the code you attach in code sandbox, i think you are trying to access input styles in two components:
AppandLabeledInput. You should use one ref in main component and use it in LabelInput component. If you still want to have separate refs then you can ref callback function and attach the node with both refs.The correct type for inputRef.current is
TextInputProps.I have updated the code sandbox. I was able to access input field styles in both components. Hope this solves your problem.