React Native Hooks
React Native Hooks
Here’s a table summarizing React Hooks and their availability in ReactJS and
React Native:
State Management
Hooks
🛠️ useState ✓ ✓ Present
🛠️ useReducer ✓ ✓ Present
🛠️
useSyncExternalStore
✓ ✘ ReactJS only
Effect Hooks
⚡ useEffect ✓ ✓ Present
⚡ useLayoutEffect ✓ ✓ Present
Ref Hooks
🪝 useRef ✓ ✓ Present
🪝 useImperativeHandle ✓ ✓ Present
Performance Hooks
⏩ useMemo ✓ ✓ Present
⏩ useCallback ✓ ✓ Present
Context Hooks
🌍 useContext ✓ ✓ Present
Transition Hooks
🚦 useTransition ✓ ✓ Present
🚦 useDeferredValue ✓ ✓ Present
🎲 useDebugValue ✓ ✓ Present
Custom Hooks
🎮useDeviceOrientation
✘ ✓ React Native only
⚙️ useFocusEffect ✘ ✓
React Native only (with
React Navigation)
Summary:
Present in both ReactJS and React Native: useState , useEffect , useReducer ,
useRef , useMemo , useCallback , useContext , useTransition , useDeferredValue ,
useDebugValue , useImperativeHandle , and Custom Hooks.
This table should give you a clear idea of which hooks are available in each
environment!
2. Toggling UI Components:
Show/hide components based on state.
3. Counter Logic:
Manage a simple counter with button presses.
How It Works:
Accepts two arguments: the reducer function and the initial state.
Returns an array: the current state and a dispatch function to update it.
// Using TextInput
<TextInput value={state.name} onChangeText={text => disp
atch({ type: 'update_name', payload: text })} />
3. Shopping Cart:
Add or remove items in a shopping cart.
Ideal for apps with complex state, like e-commerce apps or games.
How It Works:
Accepts two arguments:
useEffect(() => {
console.log("Effect ran!");
}, [dependency]);
useEffect(() => {
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => setData(data));
}, []);
useEffect(() => {
const handleOrientationChange = (event) => console.l
og(event);
Dimensions.addEventListener('change', handleOrientat
ionChange);
return () => Dimensions.removeEventListener('chang
e', handleOrientationChange);
}, []);
useEffect(() => {
setDerivedState(props.value * 2);
}, [props.value]);
Best for effects that don’t block rendering and can run after the UI update.
the DOM mutations and before the UI is painted. In React Native, this is useful
when you need to perform layout adjustments or measure dimensions before
rendering.
How It Works:
Syntax and arguments are the same as useEffect .
Runs immediately after layout changes, blocking rendering until the effect is
complete.
useLayoutEffect(() => {
const dimensions = elementRef.current?.getBoundingCl
ientRect();
console.log(dimensions);
}, []);
2. Synchronizing Scrolling:
You can scroll to a specific position after layout changes, such as scrolling
to the top of a list after data is updated.
useLayoutEffect(() => {
scrollViewRef.current?.scrollTo({ x: 0, y: scrollPos
ition, animated: true });
}, [scrollPosition]);
useLayoutEffect(() => {
elementRef.current?.setNativeProps({
style: { transform: [{ scale: 1.2 }] }
Both useEffect and useLayoutEffect help with handling side effects in React
Native, with useLayoutEffect providing a way to ensure changes are applied
immediately after the layout update, which is especially useful for animations
and layout measurements.
How It Works:
Accepts a function that returns a value and a dependency array. The
function is re-evaluated only when a dependency changes.
function ExpensiveComponent({ a, b }) {
const computedValue = useMemo(() => {
console.log("Computing...");
return a + b; // Expensive computation
}, [a, b]);
2. Derived State:
Memoize derived state based on props or state changes.
return (
<FlatList
data={filteredItems}
keyExtractor={(item) => item}
renderItem={({ item }) => <Text>{item}</Text
>}
/>
);
}
How It Works:
Accepts a function and a dependency array. Returns the same function
reference unless dependencies change.
function Parent() {
const [count, setCount] = React.useState(0);
function App() {
const [count, setCount] = React.useState(0);
return (
3. When to Use:
By applying these hooks judiciously in your React Native applications, you can
improve their performance and maintainability, even in complex scenarios with
heavy computations or event handling.
🌍 useContext
How It Works:
1. Create a Context using React.createContext .
2. Wrap your component tree with a Provider and pass a value to it.
3. Consume the context value inside any child component using useContext .
Syntax:
// Providing Context
<MyContext.Provider value={providedValue}>
<ChildComponent />
</MyContext.Provider>
// Consuming Context
const value = useContext(MyContext);
function App() {
const [isAuthenticated, setAuthenticated] = React.useSt
ate(false);
return (
<AuthContext.Provider value={{ isAuthenticated, set
Authenticated }}>
<Login />
<Dashboard />
</AuthContext.Provider>
);
}
function Login() {
const { setAuthenticated } = useContext(AuthContext);
return <Button onPress={() => setAuthenticated(true)} t
itle="Login" />;
}
function Dashboard() {
const { isAuthenticated } = useContext(AuthContext);
return <Text>{isAuthenticated ? "Welcome!" : "Please lo
g in."}</Text>;
}
Example:
function App() {
const [theme, setTheme] = React.useState("light");
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
<Header />
<Main />
</ThemeContext.Provider>
);
}
function Header() {
const { theme, setTheme } = useContext(ThemeContext);
return (
<Header>
<Button onPress={() => setTheme(theme === "ligh
t" ? "dark" : "light")}>
Switch to {theme === "light" ? "dark" : "li
ght"} mode
</Button>
</Header>
);
}
function Main() {
const { theme } = useContext(ThemeContext);
return <View style={{ backgroundColor: theme === "ligh
t" ? "#fff" : "#333" }}><Text>Current theme: {theme}</Text>
</View>;
}
Example:
function App() {
const [language, setLanguage] = React.useState("en");
return (
<LanguageContext.Provider value={{ language, setLan
guage }}>
<LanguageSwitcher />
<Content />
</LanguageContext.Provider>
);
}
function LanguageSwitcher() {
const { language, setLanguage } = useContext(LanguageCo
ntext);
return (
<Button onPress={() => setLanguage(language === "e
n" ? "es" : "en")}>
Switch to {language === "en" ? "Spanish" : "Eng
lish"}
</Button>
);
}
function Content() {
const { language } = useContext(LanguageContext);
return <Text>{language === "en" ? "Hello" : "Hola"}</Te
xt>;
}
function App() {
return (
<UserContext.Provider value="John Doe">
<Grandparent />
</UserContext.Provider>
);
}
function Grandparent() {
return <Parent />;
}
function Parent() {
return <Child />;
}
function Child() {
const userName = useContext(UserContext);
return <Text>User: {userName}</Text>;
}
Ideal for global settings that are accessed by multiple components. For
example, user authentication status or themes.
4. Application Configuration:
Store and access global settings such as API endpoints, feature toggles,
etc.
Use useContext for global state that does not change frequently. For
high-frequency updates (like real-time inputs), state management
libraries like Redux are more suitable.
4. Debugging:
By using useContext wisely, you can manage global data, prevent prop drilling,
and build clean, maintainable React Native applications.
Let’s dive into how these might work for React Native.
What It Is:
useDebugValue is a hook primarily designed for debugging custom hooks in
development. It helps you display debug information in the React DevTools for
custom hooks, making it easier to inspect the internal state of hooks during
development. Although React Native does not have full support for useDebugValue
in all scenarios, you can still use it in certain situations for debugging.
How It Works:
takes an argument (typically a value or state) and displays it in the
useDebugValue
React DevTools. This helps when you're creating custom hooks that involve
complex logic, enabling you to monitor the state or output in real-time.
useDebugValue(value)
function.
function useFetchData(url) {
const [data, setData] = useState(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
async function fetchData() {
const response = await fetch(url);
const result = await response.json();
setData(result);
setIsLoading(false);
}
fetchData();
}, [url]);
function App() {
const { data, isLoading } = useFetchData("https://jsonp
laceholder.typicode.com/posts");
if (isLoading) {
return <Text>Loading...</Text>;
}
useFetchData is a custom hook to fetch data from an API and return the data
with a loading state.
useDebugValue is used to log the isLoading state. If data is loading, you will
see "Loading..." in the DevTools, and once loaded, it will show "Data Loaded" .
Monitoring Hook State: Helps keep track of critical state within custom
hooks in React Native during development.
Regarding useId :
As of now, React Native does not support the useId hook available in React.
This hook is used in React to generate stable unique IDs, which is helpful in
scenarios like form inputs or accessibility purposes where IDs are required for
labeling or references.
Alternative for React Native:
If you need unique IDs for accessibility or other purposes, you can use
JavaScript methods like
Math.random() or libraries like uuid to generate unique IDs manually. For
example:
This provides a way to handle unique IDs in React Native while awaiting any
future updates from the React Native ecosystem.
Uses built-in hooks: It can use hooks like useState , useEffect , useContext ,
and others inside it.
Returns values or functions: Just like built-in hooks, it can return values or
functions that are needed by the components.
Encapsulates reusable logic: It organizes the logic into reusable units that
help in separating concerns.
function useWindowWidth() {
const [width, setWidth] = useState(Dimensions.get('windo
w').width);
Dimensions.addEventListener('change', handleResize);
return width;
}
In this example:
useWindowWidth is a custom hook that tracks the window’s width using React
Native's Dimensions API.
2. Separation of Concerns:
This makes the code more clean, organized, and easier to maintain.
You don't need to add state or side effect logic inside every component,
just use the custom hook wherever needed.
4. Enhanced Testability:
Custom hooks are pure JavaScript functions, which means they can
be tested independently of React Native components.
This isolation makes it easier to write unit tests for the logic without the
need for UI components.
5. Complex Operations:
1. Fetching Data
A very common use case for custom hooks is data fetching. In React Native,
this is especially useful for interacting with REST APIs or other external data
sources.
Example:
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
function App() {
const { data, loading, error } = useFetch('https://api.ex
ample.com/data');
return <Text>{JSON.stringify(data)}</Text>;
}
You can reuse useFetch in different components to fetch data from various
endpoints.
2. Form Handling
Custom hooks are also useful for form handling, which is common in React
Native apps, especially for login or registration forms.
Example:
function useForm(initialState) {
const [formData, setFormData] = useState(initialState);
function SignUp() {
const [formData, handleChange, resetForm] = useForm({ use
rname: '', email: '' });
return (
<View>
<TextInput
placeholder="Username"
name="username"
value={formData.username}
onChange={handleChange}
/>
<TextInput
placeholder="Email"
function useWindowSize() {
const [size, setSize] = useState({
width: Dimensions.get('window').width,
height: Dimensions.get('window').height,
});
useEffect(() => {
const handleResize = () => {
setSize({ width: Dimensions.get('window').width, heig
ht: Dimensions.get('window').height });
};
Dimensions.addEventListener('change', handleResize);
return () => {
return size;
}
function App() {
const { width, height } = useWindowSize();
return (
<View>
<Text>Width: {width}, Height: {height}</Text>
</View>
);
}
The useWindowSize hook tracks the window dimensions (width and height)
and can be used to adjust UI layout accordingly.
When you need to keep a component’s code clean by extracting logic that
doesn’t relate directly to rendering.
When you have complex logic that should be decoupled from the
component itself.
When you need to manage side effects or state changes outside of the
component's UI logic.
Conclusion:
Custom Hooks in React Native are a powerful tool for organizing and reusing
logic across components. They help encapsulate complex logic, improve
maintainability, and keep components clean and focused on UI rendering.
Custom hooks allow for better code organization, testing, and scalability of
your React Native applications.
Can you provide detailed notes on [your topic here], explaining it step-by-step
and including colorful and relevant emojis to make it engaging? here⇒