For my more recent React-Native projects I have been getting used to using hooks. Hooks are a fantastic feature of React/React-Native which enable us to use State in function components, in addition, they enable us to perform different functionality in our application depending on which hook we use such as useState, useRef, useEffect and useContext.
Furthermore, we can create our own hooks too which can be very useful if we are reusing a certain hook across many different components.
One of the most commonly used hooks is “useState” , State enables us to remember information about a certain part of a component and use it for other purposes i.e. we could have a piece of state to remember the text a user entered for an email address or we could have a piece of state that contains whether a value is true or false.
Throughout apps that I have made for my own personal use I have come across situations where I have had components that use the “useState” hook to remember information from a text box i.e. on a signup/signin form or on a modal. This means that I need to hold the value but also have a function that handles the text and sets the state when the user types something.
So instead of making a handle function for each text input that I use or just adding the setState function directly onto the “onChangeText” property I can add one method to a custom hook, return it from the function, then make an instance of the hook in my component and then apply the handle method of the instance onto the “onChangeText” property of the text inputs you are working with.
React hooks MUST always start with “use” followed by a capital letter i.e. useInput.
Another thing to remember is that hooks share stateful logic and not the state values themselves. So as an example, if you had 2 text inputs in one component and made 2 instances of the same custom hook to go into the 2 text inputs then both of those instances are independent of each other and wouldn’t share the state values
I will start by building an example of this and explain it, so as usual create a React-Native project (using the below command) and open it in your favourite text-editor.
npx react-native@latest init CustomHooksTutorial
So the first thing we will do with our project is to remove all the boilerplate code from App.tsx and insert 3 text inputs with some styling, your App.tsx file should look like the below.
import React from 'react';
import {
View,
StyleSheet,
TextInput,
} from 'react-native';
function App(): JSX.Element {
return (
<View style={styles.container}>
<View>
<TextInput
style={styles.textInputStyle}
placeholder='Please enter first name'
/>
</View>
<View>
<TextInput
style={styles.textInputStyle}
placeholder='Please enter last name'
/>
</View>
<View>
<TextInput
style={styles.textInputStyle}
placeholder='Please enter job title'
/>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
justifyContent: 'center', flex: 1
},
textInputStyle: {
borderColor: 'black',
borderWidth: 1,
padding: 8,
textAlign: 'center',
height: 40,
marginBottom: 20,
marginLeft:20,
marginRight:20
}
});
export default App;
So now we need to create a file called “useInput.js”, this will be our custom hook.
We will start by importing “useState” from “react” we will then create a “const” variable which has 1 parameter that it will be passed.
This parameter will be called “initialValue” and will be the initial value of the state we have in the hook.
So currently we have the below.
import { useState } from "react";
const useInput = (initialValue) => {
};
We now have to add a “useState” hook in order to contain our state value and function to update state. Call the first part “value” and the second part “setValue” and set the initial value to the “initialValue” parameter.
const [value,setValue] = useState(initialValue);
Since we are dealing with text inputs we will have to handle the “onChangeText” event of the element in order to successfully save the value to state, so we will need to make a method in the custom hook to handle this, so paste the below into the “useInput.js” file.
const handleChange = (event) => {
setValue(event);
}
In addition, I have also found it useful to have a method in the custom hook that clears the state too. This could be useful in a situation where you are submitting a form with multiple inputs are want to clear the text boxes after you have successfully submitted the form with the required values. This function would look like the below.
const clearState = () => {
setValue('');
}
The next step is to return the functionality we want so we can access them in different files. So we require the “value” state, the handle function and the clear function, we will return all 3 and give the mehods a key to access them from.
return {
value,
onChange:handleChange,
onClearState:clearState
}
Finally, export the const, so now our custom hook should look like the below.
import { useState } from "react";
const useInput = (initialValue) => {
const [value,setValue] = useState(initialValue);
const handleChange = (event) => {
setValue(event);
}
const clearState = () => {
setValue('');
}
return {
value,
onChange:handleChange,
onClearState:clearState
}
}
export default useInput;
Now navigate back to “App.tsx” and create 3 three instances of the “useInput” like below.
const firstName = useInput('');
const lastName = useInput('');
const job = useInput('');
With these 3 instances we can now access the individual return values we set in the custom hook, so we need to set the values of the TextInputs we have equal to the value of the instance like below.
<View>
<TextInput
value={firstName.value}
style={styles.textInputStyle}
placeholder='Please enter first name'
/>
</View>
<View >
<TextInput
value={lastName.value}
style={styles.textInputStyle}
placeholder='Please enter last name'
/>
</View>
<View>
<TextInput
value={job.value}
style={styles.textInputStyle}
placeholder='Please enter job title'
/>
</View>
The next thing we need to do is set the “onChangeText” equal to the handler of the instance we made of the custom hook like below.
<View>
<TextInput
value={firstName.value}
onChangeText={firstName.onChange}
style={styles.textInputStyle}
placeholder='Please enter first name'
/>
</View>
<View >
<TextInput
value={lastName.value}
onChangeText={lastName.onChange}
style={styles.textInputStyle}
placeholder='Please enter last name'
/>
</View>
<View>
<TextInput
value={job.value}
onChangeText={job.onChange}
style={styles.textInputStyle}
placeholder='Please enter job title'
/>
</View>
Ok, so that is now our TextInput sorted, we will now create another function that will show an alert that will be shown on the click of a button that we will create too.
So go to the top of the page and import “Alert” and “Button” from “react-native”.
import {
View,
StyleSheet,
TextInput,
Alert,
Button
} from 'react-native';
Now the function we create will just have a message that contains the 3 state values and a close button.
const ShowAlert = () => {
Alert.alert('Current state values', ` firstName.value = ${firstName.value}, lastName.value = ${lastName.value}, job.value = ${job.value}`,[
{
text:"Close"
}
])
}
We now need to create a button below the text boxes that will run the above function on click.
<Button title='See state values' onPress={ShowAlert} />
Now run the application and you should see the placeholders and the ability to enter text into each text box, enter some text into each of them and then click the button, you should see something similar below.
Our final piece of work to do for this article is to add a function that clears all state at once using the “onClearState” which will call the clear state in the custom hook on the click of the “Close” button on the alert.
const ClearAllState = () => {
firstName.onClearState();
lastName.onClearState();
job.onClearState();
}
Now our “ShowAlert” should look like the below.
const ShowAlert = () => {
Alert.alert('Current state values', ` firstName = ${firstName.value}, lastName = ${lastName.value}, job = ${job.value}`, [
{
text: "Close",
onPress:()=>{
ClearAllState();
}
}
])
}
If you load up your application, enter some values, click the button to show the alert then click “Close” you should see that the values in the text fields have disappeared.
That is it for this tutorial I find custom hooks a fantastic way to reduce code duplication and you can use it for much more than just text inputs. I have also used custom hooks for modals (incredibly useful due to modals usually requiring multiple types of props such as data to pass through, isVisible property and toggling of the open/close aspect of the modal) and arrays.
I may update this article in the future with more examples of custom hooks as I think that would be quite beneficial for not just others but myself too if I need a quick reminder of how they work.
Thank you for reading this article, don’t forget to clap for it and follow me on Medium.