<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Zidane Gimiga</title>
    <description>The latest articles on DEV Community by Zidane Gimiga (@zidanegimiga).</description>
    <link>https://dev.to/zidanegimiga</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F820566%2F09b68969-8d8e-4c2b-aec3-b2e641635762.jpg</url>
      <title>DEV Community: Zidane Gimiga</title>
      <link>https://dev.to/zidanegimiga</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zidanegimiga"/>
    <language>en</language>
    <item>
      <title>Building Offline-first Applications with React Native</title>
      <dc:creator>Zidane Gimiga</dc:creator>
      <pubDate>Wed, 18 Sep 2024 21:30:00 +0000</pubDate>
      <link>https://dev.to/zidanegimiga/building-offline-first-applications-with-react-native-3626</link>
      <guid>https://dev.to/zidanegimiga/building-offline-first-applications-with-react-native-3626</guid>
      <description>&lt;p&gt;Imagine your app being used by a retailer updating stock levels, a sales representative accessing customer data, or any user sending messages during intermittent connectivity. In all these cases, offline functionality can mean the difference between a seamless user experience and a frustrating one. This is where Offline-first thinking comes into play.&lt;/p&gt;

&lt;p&gt;An Offline-first approach ensures your app remains functional even when the internet is unavailable. Apps like WhatsApp illustrate this concept perfectly. When you send a message while offline, it’s stored locally and automatically sent once the connection is restored. This seamless experience is achieved by leveraging local storage and monitoring network status. Whether it's through a database or device memory, the app continues to function, syncing stored data with the server when connectivity is available again.&lt;/p&gt;

&lt;p&gt;In this article, I'll guide you through implementing offline support in React Native applications using local storage, database syncing, and Expo APIs. The benefits of an Offline-first approach include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Improved User Experience:&lt;/strong&gt; Users are less likely to experience downtime, which increases their overall satisfaction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Consistency:&lt;/strong&gt; Data is stored locally and synchronized when online, preventing data loss or corruption.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Increased Engagement:&lt;/strong&gt; Apps that work offline provide greater flexibility, increasing engagement and retention, especially in regions with unreliable internet.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Setting Up Offline Support with Expo and React Native
&lt;/h2&gt;

&lt;p&gt;Expo is a great framework for React Native development because it abstracts many platform-specific configurations, allowing you to focus on building features. In this section, we’ll explore how to implement offline support in a simple React Native app using Expo, AsyncStorage for local storage, and NetInfo for network status detection.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Set up the project
&lt;/h3&gt;

&lt;p&gt;First, let’s start by creating a new Expo-powered React Native project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-expo-app offline-first-app
cd offline-first-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Installing Dependencies
&lt;/h3&gt;

&lt;p&gt;For this example, we’ll use two key libraries:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;@react-native-async-storage/async-storage&lt;/strong&gt;: This library will allow us to store data on the device.&lt;br&gt;
&lt;strong&gt;@react-native-community/netinfo&lt;/strong&gt;: This library will help us detect network status, determining whether the device is online or offline.&lt;/p&gt;

&lt;p&gt;Install the necessary packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;expo install @react-native-async-storage/async-storage @react-native-community/netinfo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Implementing Offline Logic
&lt;/h3&gt;

&lt;p&gt;Next, we’ll build a simple application that fetches data from an API when online and stores it locally for use when offline. We will start by setting up the basic structure in App.js:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState, useEffect } from 'react';
import { StyleSheet, Text, View, Button, FlatList } from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import NetInfo from '@react-native-community/netinfo';

const DATA_API = 'https://jsonplaceholder.typicode.com/posts';

export default function App() {
  const [data, setData] = useState([]);
  const [isOffline, setIsOffline] = useState(false);

  useEffect(() =&amp;gt; {
    const loadData = async () =&amp;gt; {
      // Check network status
      const netInfo = await NetInfo.fetch();
      setIsOffline(!netInfo.isConnected);

      if (netInfo.isConnected) {
        // Fetch data from API when online
        try {
          const response = await fetch(DATA_API);
          const result = await response.json();
          setData(result);

          // Cache the data for offline use
          await AsyncStorage.setItem('cachedData', JSON.stringify(result));
        } catch (error) {
          console.error('Failed to fetch data:', error);
        }
      } else {
        // Load data from AsyncStorage when offline
        try {
          const cachedData = await AsyncStorage.getItem('cachedData');
          if (cachedData) {
            setData(JSON.parse(cachedData));
          }
        } catch (error) {
          console.error('Failed to load data from cache:', error);
        }
      }
    };

    loadData();
  }, []);

  return (
    &amp;lt;View style={styles.container}&amp;gt;
      &amp;lt;Text style={styles.header}&amp;gt;Offline-First App&amp;lt;/Text&amp;gt;
      &amp;lt;Text&amp;gt;Status: {isOffline ? 'Offline' : 'Online'}&amp;lt;/Text&amp;gt;

      &amp;lt;FlatList
        data={data}
        keyExtractor={(item) =&amp;gt; item.id.toString()}
        renderItem={({ item }) =&amp;gt; (
          &amp;lt;View style={styles.item}&amp;gt;
            &amp;lt;Text style={styles.title}&amp;gt;{item.title}&amp;lt;/Text&amp;gt;
          &amp;lt;/View&amp;gt;
        )}
      /&amp;gt;

      &amp;lt;Button title="Reload" onPress={() =&amp;gt; loadData()} /&amp;gt;
    &amp;lt;/View&amp;gt;
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    paddingTop: 50,
    paddingHorizontal: 20,
    backgroundColor: '#fff',
  },
  header: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 20,
  },
  item: {
    backgroundColor: '#f9c2ff',
    padding: 20,
    marginVertical: 8,
  },
  title: {
    fontSize: 16,
  },
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;How Does It Work?&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Network Status Detection: Using the NetInfo library, we check whether the device is online or offline. If it’s online, the app fetches data from the API and caches it. If the device is offline, the app retrieves cached data from AsyncStorage.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Data Caching: AsyncStorage allows us to store the data fetched from the API for offline access. This is essential for making the app functional without an active internet connection.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Data Synchronization: When connectivity is restored, the app fetches fresh data from the API and updates the cache, ensuring users always have the most up-to-date information when they’re online.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Advanced Offline Capabilities and Key Considerations
&lt;/h3&gt;

&lt;p&gt;You can build upon this basic functionality by integrating more advanced features, such as:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Syncing Strategies: Some apps require advanced syncing strategies, where conflicts might arise (e.g., two users updating the same data offline). Tools like PouchDB or Firebase can help manage real-time data syncing and conflict resolution.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Database Solutions: For more complex apps, you may want to use a local database like Realm or SQLite for handling larger datasets and more sophisticated queries.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Optimistic Updates: In some apps, especially those with user-generated content like social media, it’s common to allow users to create, update, or delete data offline. You can implement optimistic updates, where changes are made in the UI immediately and synced with the server when the app reconnects to the internet.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Handling Complex Syncing and Conflict Resolution
&lt;/h3&gt;

&lt;p&gt;In an offline-first app, conflicts arise when multiple users update the same data while offline and their changes are later synced with the server once the app reconnects to the internet. Handling these conflicts is crucial to maintain data consistency and provide a smooth user experience.&lt;/p&gt;

&lt;p&gt;There are different strategies for resolving such conflicts, including:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Last Write Wins (LWW)&lt;/li&gt;
&lt;li&gt;Manual Conflict Resolution&lt;/li&gt;
&lt;li&gt;Operational Transformation (OT)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I have some examples here for you to check.&lt;/p&gt;

&lt;h5&gt;
  
  
  1. Last Write Wins (LWW)
&lt;/h5&gt;

&lt;p&gt;In this strategy, the most recent change (based on a timestamp) is accepted as the final value when syncing data. It is simple and works well for many applications, but it may lead to data loss if multiple users edit the same data.&lt;/p&gt;

&lt;p&gt;Imagine you are building a note-taking app, if two users edit the same note while offline, the user who syncs their changes last will overwrite the previous user’s changes.&lt;/p&gt;

&lt;p&gt;Let’s assume we have a local storage system (using AsyncStorage) and a remote server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import AsyncStorage from '@react-native-async-storage/async-storage';

// Simulate syncing the note data with the server
const syncNoteWithServer = async (localNote) =&amp;gt; {
  try {
    const response = await fetch('evernotestefan-skliarovv1.p.rapidapi.com/getNote', {
        'x-rapidapi-key': 'Sign Up for Key',
    'x-rapidapi-host': 'Evernotestefan-skliarovV1.p.rapidapi.com',
    'Content-Type': 'multipart/form-data; boundary=---011000010111000001101001'
    });
    const serverNote = await response.json();

    // Compare timestamps
    if (localNote.updatedAt &amp;gt; serverNote.updatedAt) {
      // Local version is newer, so overwrite the server
      await fetch('https://api.example.com/note', {
        method: 'PUT',
        body: JSON.stringify(localNote),
        headers: { 'Content-Type': 'application/json' },
      });
    } else {
      // Server version is newer, discard local changes
      await AsyncStorage.setItem('note', JSON.stringify(serverNote));
    }
  } catch (error) {
    console.error('Sync failed:', error);
  }
};

// Example usage
const localNote = {
  content: 'This is an updated note.',
  updatedAt: Date.now(), // Timestamp of the last local update
};

syncNoteWithServer(localNote);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;In this example:&lt;/strong&gt;&lt;br&gt;
The app compares the updatedAt timestamp of the local note (stored offline) with the note stored on the server.&lt;br&gt;
If the local note is newer, it overwrites the server version. Otherwise, it discards local changes and updates the app with the server version.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Simple to implement.&lt;/li&gt;
&lt;li&gt;Works well for non-critical data.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;May lead to data loss (e.g., if both users made significant changes).&lt;/li&gt;
&lt;/ol&gt;
&lt;h5&gt;
  
  
  2. Manual Conflict Resolution
&lt;/h5&gt;

&lt;p&gt;With manual conflict resolution, the user is prompted to resolve conflicts when multiple versions of the same data exist. This approach is more user-friendly in scenarios where every change is valuable and users need to decide which data to keep.&lt;/p&gt;

&lt;p&gt;Here is a potential case, in a collaborative editing app, two users edit the same document while offline. Once both versions are synced, the user is prompted to choose which version to keep or merge.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import AsyncStorage from '@react-native-async-storage/async-storage';
import { Alert } from 'react-native';

// Simulate syncing the document with the server
const syncDocumentWithServer = async (localDoc) =&amp;gt; {
  try {
    const response = await fetch('https://document.com/document');
    const serverDoc = await response.json();

    if (localDoc.updatedAt !== serverDoc.updatedAt) {
      // Conflict detected, ask the user to resolve it
      Alert.alert(
        'Document Conflict',
        'Both you and another user have edited this document. Choose which version to keep.',
        [
          {
            text: 'Keep Local',
            onPress: async () =&amp;gt; {
              // Overwrite the server with local changes
              await fetch('https://api.example.com/document', {
                method: 'PUT',
                body: JSON.stringify(localDoc),
                headers: { 'Content-Type': 'application/json' },
              });
            },
          },
          {
            text: 'Keep Server',
            onPress: async () =&amp;gt; {
              // Discard local changes and update the app with the server version
              await AsyncStorage.setItem('document', JSON.stringify(serverDoc));
            },
          },
        ],
      );
    } else {
      // No conflict, proceed with syncing
      await AsyncStorage.setItem('document', JSON.stringify(serverDoc));
    }
  } catch (error) {
    console.error('Sync failed:', error);
  }
};

// Example usage
const localDoc = {
  content: 'This is my latest edit.',
  updatedAt: Date.now(), // Timestamp of the last local update
};

syncDocumentWithServer(localDoc);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Here's what's happening&lt;/strong&gt;&lt;br&gt;
If the updatedAt timestamps differ between the local and server versions, the app alerts the user and asks them to choose which version to keep. The user can decide whether to keep the local or server version.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ensures that no important data is lost.&lt;/li&gt;
&lt;li&gt;Suitable for collaborative apps where user input is valuable.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Requires user intervention, which can be disruptive.&lt;/li&gt;
&lt;li&gt;May confuse non-technical users.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;3. Operational Transformation (OT)&lt;/strong&gt;&lt;br&gt;
Operational Transformation is a more advanced technique used in real-time collaboration apps like Google Docs. It automatically merges conflicting changes by transforming operations in a way that preserves both sets of edits. OT allows multiple users to work on the same document simultaneously, and their changes are merged intelligently.&lt;/p&gt;

&lt;p&gt;In a document editor app, two users edit different parts of a document. OT ensures that both sets of edits are applied without overwriting each other.&lt;/p&gt;

&lt;p&gt;This implementation is a bit complex and require specialized libraries, such as ShareDB or Yjs. Here’s a basic pseudocode example of how OT works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Example of transforming two concurrent operations
const operation1 = { type: 'insert', position: 5, value: 'Hello' }; // User 1 adds 'Hello' at position 5
const operation2 = { type: 'insert', position: 3, value: 'World' }; // User 2 adds 'World' at position 3

const transformOperations = (op1, op2) =&amp;gt; {
  // If both operations modify different positions, no conflict
  if (op1.position !== op2.position) return [op1, op2];

  // If operations conflict, adjust positions accordingly
  if (op1.position &amp;gt; op2.position) op1.position += op2.value.length;
  else op2.position += op1.value.length;

  return [op1, op2];
};

// Transform the operations to avoid conflicts
const [transformedOp1, transformedOp2] = transformOperations(operation1, operation2);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The positions of the two conflicting operations are adjusted so that they can both be applied without overwriting each other.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ideal for real-time collaboration.&lt;/li&gt;
&lt;li&gt;Automatically resolves conflicts without user intervention.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Complex to implement.&lt;/li&gt;
&lt;li&gt;Requires specialized algorithms and libraries.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br&gt;
Each conflict resolution strategy comes with its trade-offs. For simpler apps, Last Write Wins may suffice. However, for collaborative apps where user data is crucial, Manual Conflict Resolution or more advanced techniques like Operational Transformation might be necessary. Choosing the right strategy depends on the complexity of your app and the importance of the data being modified.&lt;/p&gt;




&lt;p&gt;I plan to create a series of articles that dive deeper into the following key topics:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Optimistic UI Updates&lt;/strong&gt; – We'll explore how to immediately reflect changes made while offline in the UI, giving users the impression that their actions were successful. This approach greatly improves the user experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using Service Workers for Web-Based Apps&lt;/strong&gt; – If you're deploying your app on the web via React Native Web, I'll explain how service workers can enable offline caching and background syncing for Progressive Web Apps (PWAs). This ensures that users can access resources and data even when they’re offline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real-World Use Cases of Offline-First Apps&lt;/strong&gt; – I’ll take a closer look at how apps like Google Maps, Slack, Trello, and Notion handle offline scenarios. By studying these examples, you’ll gain a better understanding of the practical applications of offline-first techniques.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Testing Offline Capabilities&lt;/strong&gt; – We'll cover the importance of testing offline functionality and review tools like React Native Debugger, Expo tools, and the Network Link Conditioner (for iOS) to simulate network interruptions. I’ll also show you how to write tests using libraries like Jest and React Native Testing Library to ensure your app behaves correctly in offline conditions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance and Storage Considerations&lt;/strong&gt; – Performance isn’t just about speed; it’s also about user experience. I’ll discuss strategies for optimizing performance by reducing cached data and implementing data expiry policies to avoid overwhelming local storage.&lt;/p&gt;

&lt;p&gt;Stay tuned devs.&lt;/p&gt;




&lt;p&gt;Thank you for reading all the way through. I genuinely enjoy documenting and sharing my learnings. I plan to create more content, including video tutorials, which I'll share on Instagram and TikTok. If you're new here, I'm Zidane Gimiga, a software developer with a passion for optimizing user experiences. As technology becomes more integrated into our lives, it's essential to make it as easy and accessible as possible for everyone. Let's keep pushing for better, user-friendly solutions.&lt;/p&gt;

&lt;p&gt;&lt;a href="//www.github.com/zidanegimiga"&gt;Oh, I'm on Github&lt;/a&gt;&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>ux</category>
      <category>javascript</category>
    </item>
    <item>
      <title>useRef, forwardRefs and useImperativeHandle.</title>
      <dc:creator>Zidane Gimiga</dc:creator>
      <pubDate>Sun, 24 Sep 2023 09:26:32 +0000</pubDate>
      <link>https://dev.to/zidanegimiga/useref-forwardrefs-and-useimperativehandler-4dj3</link>
      <guid>https://dev.to/zidanegimiga/useref-forwardrefs-and-useimperativehandler-4dj3</guid>
      <description>&lt;p&gt;Picture this. You are creating a form on your React/React Native application, and you want an input tag to be focused as soon as the form is rendered and mounted on the screen. I'm writing to share my learnings on how to access a DOM node's property in React, control which properties of the node you would like to be exposed and be able to pass refs from a parent to a child component.&lt;/p&gt;

&lt;p&gt;Let's start with the basics. What is a ref? To put it simply, it's a label or name for a specific thing or location where something is stored. In React, you may want to access, interact and directly manipulate a DOM node like &lt;code&gt;&amp;lt;input/&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; and so on.&lt;/p&gt;

&lt;p&gt;The React library has a hook that allows you to define refs and attach them to specific DOM elements you may like. It's called &lt;code&gt;useRef&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useRef } from "react";

const Form = () =&amp;gt;{
  const inputRef = useRef(null);

  return(
    &amp;lt;form&amp;gt;
       &amp;lt;input ref={inputRef}/&amp;gt;
    &amp;lt;/form&amp;gt;
  )
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code we are importing useRef, defining a component &lt;code&gt;Form&lt;/code&gt;, adding an input tag wrapped by a form tag. We create a reference to the input tag called &lt;code&gt;inputRef&lt;/code&gt; and initialize it as &lt;code&gt;null&lt;/code&gt;. This allows us to do something cool like, focusing the input as soon as the form renders. For this, we'll utilize the &lt;code&gt;useEffect&lt;/code&gt; hook as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useRef, useEffect } from "react";

const Form = () =&amp;gt;{
  const inputRef = useRef(null);

  useEffect(()=&amp;gt;{
    inputRef.current.focus();    
  }, [])

  return(
    &amp;lt;form&amp;gt;
       &amp;lt;input ref={inputRef}/&amp;gt;
    &amp;lt;/form&amp;gt;
  )
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the ref, you can perform more things like setting style properties e.g&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  inputRef.current.style.borderColor = "green";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It basically exposes all of the properties of a DOM node to you.&lt;/p&gt;

&lt;p&gt;Now, let's say you are creating a &lt;code&gt;MyInput&lt;/code&gt; component because of your design system and it's also a best practice to create reusable components in React so as to avoid code duplication.&lt;/p&gt;

&lt;p&gt;Being this independent, you can pass a ref to a specific input component. For this, we utilize forwardRef.&lt;/p&gt;

&lt;p&gt;Your input component might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { forwardRef } from "react";

const MyInput = forwardRef(function MyInput(ref, props)){
  return(
    &amp;lt;input 
     value={props.value}
    /&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will then use it in the &lt;code&gt;Form&lt;/code&gt; component by passing a ref as a prop to the &lt;code&gt;MyInput&lt;/code&gt; component. This will allow you to immediately focus the specific input field as soon as the Form renders. You could perform extra things like when a user enters an invalid value or attempts to submit values without filling a field, then you could scroll to and focus on that field, and perhaps change the border color to red. Refs open you up to special conditional customizations of your DOM elements.&lt;/p&gt;

&lt;p&gt;Let's say you want to hide some functions or values from the Parent &lt;code&gt;Form&lt;/code&gt; component. You could also want to create custom functions that bundle together different ref functions that the Form component can use. I will introduce you to a React hook called &lt;code&gt;useImperativeHandler&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The hook is a way to control what properties and methods are accessible from a child component when accessed through a ref.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useRef, useImperativeHandle, forwardRef } from 'react';

const MyInput = forwardRef((props, ref) =&amp;gt; {
  const inputRef = useRef();

  useImperativeHandle(ref, () =&amp;gt; ({
    focus: () =&amp;gt; {
      inputRef.current.focus();
    },
    getValue: () =&amp;gt; {
      return inputRef.current.value;
    },
  }));

  return &amp;lt;input ref={inputRef} /&amp;gt;;
});

const Form = () =&amp;gt; {
  const childRef = useRef();

  const handleFocus = () =&amp;gt; {
    // This will call the custom focus method in the child component
    childRef.current.focus(); 
  };

  const handleGetValue = () =&amp;gt; {
    // This will call the custom getValue method in the child component
    const value = childRef.current.getValue(); 
    console.log('Value:', value);
  };

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;MyInput ref={childRef} /&amp;gt;
      &amp;lt;button onClick={handleFocus}&amp;gt;Focus Input&amp;lt;/button&amp;gt;
      &amp;lt;button onClick={handleGetValue}&amp;gt;Get Value&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the Input component uses useImperativeHandle to customize the interface exposed through the ref. It exposes a focus method to focus on the input field and a getValue method to retrieve its value. The Form component can then use these methods through the childRef.&lt;/p&gt;

&lt;p&gt;This approach allows you to encapsulate and control the interactions with a child component, exposing only the necessary functionality to the parent component through the ref.&lt;/p&gt;

&lt;p&gt;Please refer to the following links for more in depth information regarding refs in React.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://react.dev/reference/react/useRef" rel="noopener noreferrer"&gt;useRef&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://react.dev/reference/react/useImperativeHandle" rel="noopener noreferrer"&gt;useImperativeHandle&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;I am &lt;a href="https://www.linkedin.com/in/zidane-gimiga-976379135/" rel="noopener noreferrer"&gt;Zidane Gimiga&lt;/a&gt;, a full Stack software engineer and fervent Web3 enthusiast. I am committed to sharing different things I learn with others, mostly in software development. I hope you found value in this or had your interest piqued. Please feel free to ask questions or share your feedback. Until next time!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>reactnative</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
