This might be a common requirement that sometimes in our forms we need to add or remove input fields dynamically and each input field needs to be attached with its corresponding value. Recently I have implemented this. We can do it in different ways. So here goes my implementation.
In order to achieve this first, I declare 2 states and 1 ref.
// this will be attached with each input onChangeText
const [textValue, setTextValue] = useState('');
// our number of inputs, we can add the length or decrease the length
const [numInputs, setNumInputs] = useState(1);
// all our input fields are tracked with this array
const refInputs = useRef<string[]>([textValue]);
Okay, now we need a loop to iterate until our numInputs and generate the inputs that many times.
const inputs: JSX.Element[] = [];
for (let i = 0; i < numInputs; i ++)
{
inputs.push(
<View key={i} style={{flexDirection: 'row', alignItems: 'center'}}>
<Text>{i + 1}.</Text>
<TextInput
style={styles.input}
onChangeText={value => setInputValue(i, value)}
value={refInputs.current[i]}
placeholder="placeholder"
/>
{/* To remove the input */}
<Pressable onPress={() => removeInput(i)} style={{marginLeft: 5}}>
<AntDesign name="minuscircleo" size={20} color="red" />
</Pressable>
</View>
);
}
and this is our render JSX.
<ScrollView contentContainerStyle={styles.container}>
{inputs}
<Pressable onPress={addInput} style={styles.addButton}>
<Text style={{color: 'white', fontWeight: 'bold'}}>+ Add a new input</Text>
</Pressable>
<View style={{ marginTop: 25 }}>
<Text>You have answered:</Text>
{refInputs.current.map((value, i) => {
return <Text key={i} style={styles.answer}>{`${i+ 1} - ${value}`}</Text>
})}
</View>
</ScrollView>
Since initially, our numInputs is 1, we get 1 TextInput and a button to add more inputs.
Cool, now we need three functions.
- setInputValue -> is to set the input fields value.
const setInputValue = (index: number, value: string) => {
// first, we are storing input value to refInputs array to track them
const inputs = refInputs.current;
inputs[index] = value;
// we are also setting the text value to the input field onChangeText
setTextValue(value)
}
- addInput -> add a new input when the add input button is pressed.
const addInput = () => {
// add a new element in our refInputs array
refInputs.c urrent.push('');
// increase the number of inputs
setNumInputs(value => value + 1);
}
- removeInput -> remove input when minus icon is pressed.
const removeInput = (i: number) => {
// remove from the array by index value
refInputs.current.splice(i, 1)[0];
// decrease the number of inputs
setNumInputs(value => value - 1);
}
We are done! With all of these, we get the following output
Here is a working demo for you to play with.
hi hi. just want to ask, how to change this code from functional component into class component? ” const refInputs = useRef([textValue]); ” how to use useRef in class component?
You can not use useRef inside any class component. useRef is a hook and can only be used in the functional component.