<?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: Mohamed Elgazzar</title>
    <description>The latest articles on DEV Community by Mohamed Elgazzar (@thisisgazzar).</description>
    <link>https://dev.to/thisisgazzar</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%2F964007%2F896dc23b-b4b1-425a-98e5-6db0bed411c6.jpeg</url>
      <title>DEV Community: Mohamed Elgazzar</title>
      <link>https://dev.to/thisisgazzar</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/thisisgazzar"/>
    <language>en</language>
    <item>
      <title>Build an AI Image Captioner with React Native &amp; Hugging Face + Unit Testing</title>
      <dc:creator>Mohamed Elgazzar</dc:creator>
      <pubDate>Sun, 04 Feb 2024 22:40:46 +0000</pubDate>
      <link>https://dev.to/thisisgazzar/build-an-ai-image-captioner-with-react-native-hugging-face-unit-testing-5535</link>
      <guid>https://dev.to/thisisgazzar/build-an-ai-image-captioner-with-react-native-hugging-face-unit-testing-5535</guid>
      <description>&lt;p&gt;Hey there!👋 After a bit of a hiatus, I'm back and ready to dive into some coding fun. &lt;strong&gt;In this article&lt;/strong&gt;, we'll be building something exciting – an AI Image Captioning App using &lt;strong&gt;React Native&lt;/strong&gt; and &lt;strong&gt;the Hugging Face Inference API&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;Without any more delays, let the coding begin! We will be using &lt;strong&gt;Expo&lt;/strong&gt; to bootstrap our React Native project. Expo is a set of tools and services for building React Native applications more easily and quickly.&lt;/p&gt;

&lt;p&gt;Before we kick things off, make sure you have &lt;strong&gt;Node.js&lt;/strong&gt; installed on your machine.&lt;/p&gt;

&lt;p&gt;To initialize a new project, run the following command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npx create-expo-app ai-image-captioner &amp;amp;&amp;amp; cd ai-image-captioner&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After navigating to the project directory, install the following dependencies: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;npx expo install expo-camera expo-image-picker expo-font expo-splash-screen&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install axios&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;axios&lt;/strong&gt;: axios is a promise-based HTTP client for the browser and Node.js. It is commonly used for making HTTP requests and handling responses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;expo-camera&lt;/strong&gt;: expo-camera is a part of the Expo framework, providing a set of components and APIs for integrating camera functionality into React Native applications. It simplifies the process of capturing photos and videos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;expo-image-picker&lt;/strong&gt;: expo-image-picker is another Expo package that facilitates accessing the device's image and video picker. It allows users to choose images or videos from their device's gallery for use within the application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;expo-font&lt;/strong&gt;: expo-font is an Expo module that simplifies the process of loading custom fonts in React Native applications. It provides tools to easily incorporate and use custom fonts for styling text elements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;expo-splash-screen&lt;/strong&gt;: expo-splash-screen is an Expo-specific module designed to manage the splash screen (initial screen displayed while the app is loading) in React Native applications. It offers an easy way to customize and control the splash screen experience.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Hugging Face:
&lt;/h2&gt;

&lt;p&gt;Hugging Face is a machine learning and data science platform and community that helps users build, deploy and train machine learning models.&lt;/p&gt;

&lt;p&gt;Hugging Face offers a diverse array of tools, models, and datasets that empower developers and researchers in the field of machine learning. Their platform is home to an extensive library of pre-trained models, facilitating easy integration and experimentation for professionals working in artificial intelligence.&lt;/p&gt;

&lt;p&gt;Let's head to &lt;a href="https://huggingface.co/" rel="noopener noreferrer"&gt;the Hugging Face official website&lt;/a&gt; and create an account.&lt;/p&gt;

&lt;p&gt;Once you have created your account, you can navigate to &lt;a href="https://huggingface.co/settings/tokens" rel="noopener noreferrer"&gt;access tokens&lt;/a&gt; and generate one.&lt;/p&gt;

&lt;p&gt;Copy it and set it aside. We will use it in a few moments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pre-trained models:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A pre-trained model is a machine learning (ML) model that has been trained on a large dataset and can be fine-tuned for a specific task.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://huggingface.co/models" rel="noopener noreferrer"&gt;The Model Hub&lt;/a&gt; allows users to discover, share, and use pre-trained models for various tasks.&lt;/p&gt;

&lt;p&gt;There are various approaches to integrate pre-trained models seamlessly. For a quick and straightforward implementation, we are going to use the Inference API. However, if your project demands a higher level of customization and control, you can use the &lt;a href="https://huggingface.co/docs/transformers/en/index" rel="noopener noreferrer"&gt;Transformers&lt;/a&gt; library.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Inference API&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When opting for the Inference API, you have two pathways. You can either incorporate the huggingface/inference package into your project for a streamlined experience, or take advantage of direct API access by defining the endpoint variable, such as: &lt;code&gt;ENDPOINT = https://api-inference.huggingface.co/models/&amp;lt;MODEL_ID&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Our app consists of a few components, but the heart of the operation lies in App.js. Copy the code below into the file:&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 } from "react";
import axios from "axios";
import ImageForm from "./components/ImageForm";

const App = () =&amp;gt; {
  const [caption, setCaption] = useState("");

  const handleImageUrl = async (imageUrl) =&amp;gt; {
    try {
      let image = await (await fetch(imageUrl)).blob();
      const HUGGING_FACE_API_KEY = "HUGGING_FACE_API_KEY";
      const response = await axios.post(
        "https://api-inference.huggingface.co/models/nlpconnect/vit-gpt2-image-captioning",
        image,
        {
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${HUGGING_FACE_API_KEY}`,
          },
          transformRequest: [(data) =&amp;gt; data],
        }
      );
      setCaption(response.data[0].generated_text);
    } catch (error) {
      console.error(error);
    }
  };

  return &amp;lt;ImageForm onSubmit={handleImageUrl} caption={caption} /&amp;gt;;
};

export default App;

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

&lt;/div&gt;



&lt;p&gt;Now let's break down some key parts:&lt;/p&gt;

&lt;p&gt;Here, we import React and useState from React for our component's state management. Additionally, we bring in axios for making HTTP requests and ImageForm, a component we'll create to handle image processing. Then, we declare the App component and using the useState hook, we set up a state variable caption and its corresponding setter function setCaption.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;handleImageUrl&lt;/code&gt;, is where the real action happens. It takes an imageUrl as an argument, fetches the image, and makes a POST request to the Inference API. We used the &lt;code&gt;nlpconnect/vit-gpt2-image-captioning&lt;/code&gt; model for image captioning. The result is stored in the caption state.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;code&gt;transformRequest: [(data) =&amp;gt; data]&lt;/code&gt; in the axios request is used to disable automatic data serialization, and send data in its raw form.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Finally, in the return statement, we render the ImageForm component, passing down the handleImageUrl function and the caption state as props.&lt;/p&gt;

&lt;p&gt;Create a new &lt;code&gt;ImageForm.js&lt;/code&gt; file with the following content:&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, useCallback } from "react";
import {
  View,
  TextInput,
  TouchableOpacity,
  Image,
  Text,
  ActivityIndicator,
  StyleSheet,
  Alert,
} from "react-native";
import { Camera, CameraType } from "expo-camera";
import { useFonts } from "expo-font";
import * as ImagePicker from "expo-image-picker";
import * as SplashScreen from "expo-splash-screen";
import CameraScreen from "./CameraScreen";
import { Preview } from "../assets";

SplashScreen.preventAutoHideAsync();

const ImageForm = ({ onSubmit, caption }) =&amp;gt; {
  const [imageUrl, setImageUrl] = useState(null);
  const [selectedImage, setSelectedImage] = useState(null);
  const [loading, setLoading] = useState(false);

  const [toggleCamera, setToggleCamera] = useState(false);
  const [capturedImage, setCapturedImage] = useState(null);
  const [permission, requestPermission] = Camera.useCameraPermissions();
  const [type, setType] = useState(CameraType.back);

  const [fontsLoaded, fontError] = useFonts({
    "BebasNeue-Regular": require("../assets/fonts/BebasNeue-Regular.ttf"),
  });

  useEffect(() =&amp;gt; {
    // Request permission to access the photo library
    (async () =&amp;gt; {
      const { status } =
        await ImagePicker.requestMediaLibraryPermissionsAsync();
      if (status !== "granted") {
        Alert.alert(
          "Permission denied",
          "You need to grant permission to access the photo library."
        );
      }
    })();
  }, []);

  const pickImage = async () =&amp;gt; {
    try {
      const result = await ImagePicker.launchImageLibraryAsync({
        mediaTypes: ImagePicker.MediaTypeOptions.Images,
        allowsEditing: true,
        aspect: [4, 3],
        quality: 1,
      });
      if (!result.cancelled) {
        setSelectedImage(result.assets[0].uri);
        setImageUrl(result.assets[0].uri);
      }
    } catch (error) {
      console.error(error);
    }
  };

  const handlePress = async () =&amp;gt; {
    setLoading(true);
    await onSubmit(imageUrl);
    setLoading(false);
  };

  const submitImage = () =&amp;gt; {
    setToggleCamera(!toggleCamera);
  };
  const cancelCamera = () =&amp;gt; {
    setToggleCamera(!toggleCamera);
    setImageUrl("");
    setCapturedImage(null);
    setSelectedImage(null);
  };

  const onLayoutRootView = useCallback(async () =&amp;gt; {
    if (fontsLoaded || fontError) {
      await SplashScreen.hideAsync();
    }
  }, [fontsLoaded, fontError]);

  if (!fontsLoaded &amp;amp;&amp;amp; !fontError) {
    return null;
  }

  return (
    &amp;lt;View style={styles.wrapper} onLayout={onLayoutRootView}&amp;gt;
      {toggleCamera ? (
        &amp;lt;CameraScreen
          cancelCamera={cancelCamera}
          setImageUrl={setImageUrl}
          submitImage={submitImage}
          capturedImage={capturedImage}
          setCapturedImage={setCapturedImage}
          requestPermission={requestPermission}
          permission={permission}
          type={type}
          setSelectedImage={setSelectedImage}
        /&amp;gt;
      ) : (
        &amp;lt;View style={styles.container}&amp;gt;
          &amp;lt;View&amp;gt;
            &amp;lt;Text style={[styles.textStyle, styles.header]}&amp;gt;
              Image Captioner! 🤗
            &amp;lt;/Text&amp;gt;
          &amp;lt;/View&amp;gt;

          &amp;lt;View style={styles.imagePreviewContainer}&amp;gt;
            &amp;lt;Image
              source={ selectedImage ? { uri: selectedImage } : Preview }
              style={[styles.imagePreview, !selectedImage &amp;amp;&amp;amp; { width: 100 }]}
              resizeMode="contain"
            /&amp;gt;
          &amp;lt;/View&amp;gt;

          &amp;lt;View&amp;gt;
            &amp;lt;Text style={[styles.textStyle, { fontWeight: "bold" }]}&amp;gt;
              {caption !== "" &amp;amp;&amp;amp; "🪄 " + caption + " 🪄"}
            &amp;lt;/Text&amp;gt;
          &amp;lt;/View&amp;gt;

          &amp;lt;View style={styles.inputContainer}&amp;gt;
            &amp;lt;TextInput
              style={styles.inputBox}
              autoCapitalize="none"
              placeholder="Enter Image Link"
              value={imageUrl}
              onChangeText={(url) =&amp;gt; setImageUrl(url)}
            /&amp;gt;
          &amp;lt;/View&amp;gt;

          &amp;lt;View&amp;gt;
            &amp;lt;Text
              style={{
                fontSize: 20,
                fontWeight: "bold",
                textAlign: "center",
                color: "#8C94A5",
                marginVertical: 10,
              }}
            &amp;gt;
              OR
            &amp;lt;/Text&amp;gt;
          &amp;lt;/View&amp;gt;

          &amp;lt;View style={styles.buttonArea}&amp;gt;
            &amp;lt;TouchableOpacity
              style={[
                styles.button,
                { backgroundColor: "#0166FF" },
              ]}
              onPress={submitImage}
            &amp;gt;
              &amp;lt;Text style={styles.ButtonText}&amp;gt;Take Photo&amp;lt;/Text&amp;gt;
            &amp;lt;/TouchableOpacity&amp;gt;
          &amp;lt;/View&amp;gt;

          &amp;lt;View style={styles.buttonArea}&amp;gt;
            &amp;lt;TouchableOpacity
              style={[styles.button, { backgroundColor: "#0166FF" }]}
              onPress={pickImage}
            &amp;gt;
              &amp;lt;Text style={styles.ButtonText}&amp;gt;Browse Images&amp;lt;/Text&amp;gt;
            &amp;lt;/TouchableOpacity&amp;gt;
          &amp;lt;/View&amp;gt;

          &amp;lt;View style={styles.lineStyle} /&amp;gt;

          &amp;lt;View style={[styles.buttonArea, styles.submitBtnArea]}&amp;gt;
            &amp;lt;TouchableOpacity
              style={[styles.button, { backgroundColor: "#212429" }]}
              onPress={handlePress}
            &amp;gt;
              &amp;lt;Text style={styles.ButtonText}&amp;gt;Process&amp;lt;/Text&amp;gt;
            &amp;lt;/TouchableOpacity&amp;gt;
          &amp;lt;/View&amp;gt;

          {loading &amp;amp;&amp;amp; (
            &amp;lt;ActivityIndicator
              size="large"
              color="#0000FF"
              style={styles.loading}
            /&amp;gt;
          )}
        &amp;lt;/View&amp;gt;
      )}
    &amp;lt;/View&amp;gt;
  );
};

const styles = StyleSheet.create({
  wrapper: {
    height: "100%",
    paddingHorizontal: 30,
    paddingVertical: 80,
  },
  container: {
    height: "100%",
  },
  header: {
    fontWeight: 700,
    fontSize: 35,
    fontFamily: "BebasNeue-Regular",
    color: "#29323B",
  },
  textStyle: {
    fontSize: 14,
    marginTop: 8,
    marginBottom: 5,
    textAlign: "center",
    color: "#29323B",
  },
  inputContainer: {
    marginTop: 20,
  },
  inputBox: {
    borderColor: "#E1E4EB",
    height: 55,
    width: "100%",
    borderRadius: 10,
    borderWidth: 2,
    padding: 10,
    textAlign: "left",
  },
  button: {
    backgroundColor: "blue",
    height: 40,
    width: "100%",
    borderRadius: 5,
    padding: 10,
  },
  buttonArea: {
    display: "flex",
    alignItems: "center",
    justifyContent: "center",
    marginBottom: 5,
  },
  submitBtnArea: {
    marginVertical: 10,
  },
  ButtonText: {
    color: "white",
    textAlign: "center",
  },
  loading: {
    marginTop: 8,
  },
  imagePreviewContainer: {
    alignItems: "center",
    marginBottom: 16,
    marginTop: 16,
    width: "100%",
    height: 200,
    borderWidth: 2,
    borderStyle: "dashed",
    borderColor: "#7BA7FF",
    borderRadius: 5,
  },
  imagePreview: {
    borderRadius: 5,
    width: "100%",
    height: "100%",
  },
  lineStyle: {
    borderWidth: 0.5,
    borderColor: "#D3D8E3",
    marginBottom: 15,
    marginTop: 10,
  },
});

export default ImageForm;


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

&lt;/div&gt;



&lt;p&gt;We first import necessary modules and components for the &lt;code&gt;ImageForm&lt;/code&gt; component.&lt;/p&gt;

&lt;p&gt;Then, we configure SplashScreen that invokes &lt;code&gt;preventAutoHideAsync&lt;/code&gt; to prevent the splash screen from hiding until fonts are loaded.&lt;/p&gt;

&lt;p&gt;After that, we initialize state variables using useState for managing the component's state.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;toggleCamera&lt;/code&gt; state manages whether the camera is active.&lt;br&gt;
&lt;code&gt;permission&lt;/code&gt; and &lt;code&gt;requestPermission&lt;/code&gt; manage camera permissions.&lt;br&gt;
&lt;code&gt;type&lt;/code&gt; manages the camera type (front/back).&lt;br&gt;
&lt;code&gt;useFonts&lt;/code&gt; loads custom fonts, with error handling.&lt;br&gt;
&lt;code&gt;useEffect&lt;/code&gt; hook here is used to request permission to access the photo library when the component mounts.&lt;/p&gt;

&lt;p&gt;We use the &lt;code&gt;useFonts&lt;/code&gt; hook from Expo to import the "BebasNeue-Regular" font and load it. The &lt;code&gt;onLayoutRootView&lt;/code&gt; function, using useCallback, hides the splash screen when fonts are loaded. If fonts are not yet loaded, it returns null to prevent rendering.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pickImage&lt;/code&gt; function uses &lt;code&gt;ImagePicker&lt;/code&gt; from Expo to launch the device's image library. It configures the picker with options like allowed media types, editing capabilities, aspect ratio, and quality. If the user selects an image (!result.cancelled), it updates the state variables setSelectedImage and setImageUrl with the URI of the selected image.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;handlePress&lt;/code&gt; function is triggered when the user presses the &lt;code&gt;Process&lt;/code&gt; button to submit the image for processing. It sets the loading state to true to show an activity indicator. Calls the onSubmit function (provided as a prop) with the &lt;code&gt;imageUrl&lt;/code&gt; as an argument, which triggers the image processing logic.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;submitImage&lt;/code&gt; function toggles the camera screen.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cancelCamera&lt;/code&gt; function when the user cancels or exits the camera screen.&lt;/p&gt;

&lt;p&gt;The UI is conditionally rendered based on the &lt;code&gt;toggleCamera&lt;/code&gt; state. If &lt;code&gt;toggleCamera&lt;/code&gt; is true, it shows the &lt;code&gt;CameraScreen&lt;/code&gt;, passing various props for handling the camera functionality; otherwise, it displays the main &lt;code&gt;ImageForm&lt;/code&gt; UI.&lt;/p&gt;

&lt;p&gt;Finally, create a new &lt;code&gt;CameraScreen.js&lt;/code&gt; file and copy the following code into it:&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 from "react";
import {
  View,
  Text,
  TouchableOpacity,
  Image,
  StyleSheet,
  Button,
} from "react-native";
import { Camera } from "expo-camera";
import { Capture, Submit, Back, Reset } from "../assets";

const CameraScreen = ({
  cancelCamera,
  submitImage,
  setImageUrl,
  capturedImage,
  setCapturedImage,
  setSelectedImage,
  permission,
  type,
}) =&amp;gt; {
  const takePicture = async () =&amp;gt; {
    if (cameraRef) {
      const photo = await cameraRef.takePictureAsync();
      setCapturedImage(photo);
      setImageUrl(photo.uri);
      setSelectedImage(photo.uri);
    }
  };

  const resetImage = () =&amp;gt; {
    setCapturedImage(null);
    setImageUrl(null);
    setSelectedImage(null);
  };

  if (!permission) {
    // Camera permissions are still loading
    return &amp;lt;View /&amp;gt;;
  }

  if (!permission.granted) {
    // Camera permissions are not granted yet
    return (
      &amp;lt;View style={styles.container}&amp;gt;
        &amp;lt;Text style={{ textAlign: "center" }}&amp;gt;
          We need your permission to show the camera
        &amp;lt;/Text&amp;gt;
        &amp;lt;Button onPress={requestPermission} title="grant permission" /&amp;gt;
      &amp;lt;/View&amp;gt;
    );
  }

  return (
    &amp;lt;View style={styles.container} testID="camera-screen"&amp;gt;
      &amp;lt;Camera
        style={styles.camera}
        type={type}
        ref={(ref) =&amp;gt; (cameraRef = ref)}
      &amp;gt;
        &amp;lt;View style={styles.buttonContainer}&amp;gt;
          &amp;lt;TouchableOpacity
            style={styles.button}
            onPress={takePicture}
            testID="capture-button"
          &amp;gt;
            &amp;lt;Image
              source={Capture}
              style={styles.imageIcon}
              resizeMode="contain"
            /&amp;gt;
          &amp;lt;/TouchableOpacity&amp;gt;
          &amp;lt;TouchableOpacity style={styles.button} onPress={cancelCamera}&amp;gt;
            &amp;lt;Image
              source={Back}
              style={styles.imageIcon}
              resizeMode="contain"
            /&amp;gt;
          &amp;lt;/TouchableOpacity&amp;gt;
          {capturedImage &amp;amp;&amp;amp; (
            &amp;lt;TouchableOpacity style={styles.button} onPress={resetImage}&amp;gt;
              &amp;lt;Image
                source={Reset}
                style={styles.imageIcon}
                resizeMode="contain"
              /&amp;gt;
            &amp;lt;/TouchableOpacity&amp;gt;
          )}
          {capturedImage &amp;amp;&amp;amp; (
            &amp;lt;TouchableOpacity style={styles.button} onPress={submitImage}&amp;gt;
              &amp;lt;Image
                source={Submit}
                style={styles.imageIcon}
                resizeMode="contain"
              /&amp;gt;
            &amp;lt;/TouchableOpacity&amp;gt;
          )}
        &amp;lt;/View&amp;gt;
      &amp;lt;/Camera&amp;gt;

      {capturedImage &amp;amp;&amp;amp; (
        &amp;lt;View style={styles.imagePreviewContainer}&amp;gt;
          &amp;lt;Text style={{ textAlign: "center", marginBottom: 15 }}&amp;gt;
            Captured Image Preview
          &amp;lt;/Text&amp;gt;
          &amp;lt;Image
            source={{ uri: capturedImage.uri }}
            style={styles.imagePreview}
          /&amp;gt;
        &amp;lt;/View&amp;gt;
      )}
    &amp;lt;/View&amp;gt;
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  camera: {
    flex: 1,
  },
  buttonContainer: {
    flex: 1,
    flexDirection: "row",
    backgroundColor: "transparent",
    margin: 64,
  },
  button: {
    flex: 1,
    alignSelf: "flex-end",
    alignItems: "center",
  },
  cameraContainer: {
    flex: 1,
    flexDirection: "column",
    justifyContent: "space-between",
    margin: 20,
    width: "100%",
  },
  buttonText: {
    fontSize: 18,
    color: "white",
  },
  imagePreviewContainer: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
  },
  imagePreview: {
    width: "80%",
    height: "80%",
    resizeMode: "contain",
  },
  imageIcon: {
    width: 30,
    height: 30,
  },
});

export default CameraScreen;

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

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;takePicture&lt;/code&gt; function captures a photo using the cameraRef and updates state variables (setCapturedImage, setImageUrl, setSelectedImage).&lt;br&gt;
&lt;code&gt;resetImage&lt;/code&gt; function resets the captured image and associated state variables.&lt;/p&gt;

&lt;p&gt;Then we check whether camera permissions are still loading or not granted. Renders a message to grant permission if needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Congratulations on making it this far! Now, let's perform some unit testing to ensure our code behaves as expected.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Unit Testing:
&lt;/h2&gt;

&lt;p&gt;Before we dive into the testing arena, let's make sure our environment is prepared. Ensure you have the necessary packages in your toolkit:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npx expo install jest-expo jest&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install -D @testing-library/react-native&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;jest&lt;/strong&gt;: jest is a JavaScript testing framework widely used for testing JavaScript code, including React and React Native applications. It provides a test runner, assertion library, and mocking capabilities.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;jest-expo&lt;/strong&gt;: jest-expo is a Jest preset specifically designed for Expo projects. It configures Jest with settings optimized for Expo and React Native development, making it easier to write and run tests in Expo projects.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;@testing-library/react-native&lt;/strong&gt;: @testing-library/react-native is part of the Testing Library family and provides utilities for testing React Native components. It encourages testing components in a way that simulates user interactions and ensures the application behaves as expected.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Include the Jest configuration in your &lt;code&gt;package.json&lt;/code&gt; file like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...

"scripts": {
    ...
    "test": "jest"
},
"jest": {
    "preset": "jest-expo",
    "transformIgnorePatterns": [
      "node_modules/(?!((jest-)?react-native|@react-native(-community)?)|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base|react-native-svg)"
    ]
  },

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

&lt;/div&gt;



&lt;p&gt;This configuration ensures that Jest ignores certain modules during the transformation process, preventing potential issues with Expo and related dependencies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Writing Our Script&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create a &lt;code&gt;App.test.js&lt;/code&gt; file with the following content:&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 from "react";
import axios from "axios";
import { render, waitFor, fireEvent, act } from "@testing-library/react-native";
import { Camera } from "expo-camera";
import ImageForm from "./ImageForm";
import App from "./App";

jest.mock("axios");

jest.mock("expo-image-picker", () =&amp;gt; ({
  ...jest.requireActual("expo-image-picker"),
  requestMediaLibraryPermissionsAsync: jest.fn(),
}));

describe("App", () =&amp;gt; {
  describe("ImageForm Component", () =&amp;gt; {
    it("renders correctly", async () =&amp;gt; {
      require("expo-image-picker").requestMediaLibraryPermissionsAsync.mockResolvedValue(
        {
          status: "granted",
        }
      );

      const { getByText, getByPlaceholderText } = render(&amp;lt;ImageForm /&amp;gt;);

      await waitFor(() =&amp;gt; {
        expect(getByText("Image Captioner! 🤗")).toBeTruthy();
      });
      await waitFor(() =&amp;gt; {
        expect(getByPlaceholderText("Enter Image Link")).toBeTruthy();
      });
    });

    it("handles submit button press correctly", async () =&amp;gt; {
      const mockOnSubmit = jest.fn();
      const { getByPlaceholderText, getByText, getByTestId } = render(
        &amp;lt;ImageForm onSubmit={mockOnSubmit} /&amp;gt;
      );

      const input = getByPlaceholderText("Enter Image Link");
      const submitButton = getByText("Process");

      fireEvent.changeText(input, "https://example.com/image.jpg");

      fireEvent.press(submitButton);

      await waitFor(() =&amp;gt; {
        expect(mockOnSubmit).toHaveBeenCalledWith(
          "https://example.com/image.jpg"
        );
      });
    });

    it("handles image URL submission and displays the generated caption", async () =&amp;gt; {
      const mockCaption = "Mock Caption";
      axios.post.mockResolvedValue({ data: [{ generated_text: mockCaption }] });
      const { getByPlaceholderText, getByText } = render(&amp;lt;App /&amp;gt;);
      const input = getByPlaceholderText("Enter Image Link");
      await act(() =&amp;gt; {
        fireEvent.changeText(input, "https://example.com/image.jpg");
      });
      await act(() =&amp;gt; {
        const submitButton = getByText("Process");
        fireEvent.press(submitButton);
      });
      await waitFor(() =&amp;gt;
        expect(getByText(`🪄 ${mockCaption} 🪄`)).toBeTruthy()
      );
    });
  });

  describe("CameraScreen Component", () =&amp;gt; {
    it("shows camera if permissions are granted", async () =&amp;gt; {
      jest
        .spyOn(Camera, "useCameraPermissions")
        .mockReturnValue([{ granted: true }, () =&amp;gt; Promise.resolve({})]);

      const { getByTestId, getByText } = render(&amp;lt;App /&amp;gt;);
      await act(() =&amp;gt; {
        fireEvent.press(getByText("Take Photo"));
      });

      const camera = getByTestId("camera-screen");
      expect(camera).toBeTruthy();
    });

    it("takes a picture and displays preview", async () =&amp;gt; {
      jest
        .spyOn(Camera, "useCameraPermissions")
        .mockReturnValue([{ granted: true }, () =&amp;gt; Promise.resolve({})]);

      jest
        .spyOn(Camera.prototype, "takePictureAsync")
        .mockImplementation(() =&amp;gt; {
          return Promise.resolve({
            uri: "file://some-file.jpg",
          });
        });

      const { getByTestId, getByText } = render(&amp;lt;App /&amp;gt;);

      fireEvent.press(getByText("Take Photo"));

      const captureButton = getByTestId("capture-button");

      fireEvent.press(captureButton);
      await waitFor(() =&amp;gt; {
        expect(getByText("Captured Image Preview")).toBeTruthy();
      });
    });
  });
});

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

&lt;/div&gt;



&lt;p&gt;Mocking Axios and Expo's image picker is also for testing purposes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"renders correctly":&lt;/strong&gt;&lt;br&gt;
The test sets up a mock for &lt;code&gt;requestMediaLibraryPermissionsAsync&lt;/code&gt; to simulate the permission being granted. Then, it renders the ImageForm component, and asserts that the component renders the expected text "Image Captioner! 🤗" and includes a placeholder for entering an image link.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"handles submit button press correctly":&lt;/strong&gt;&lt;br&gt;
It creates a mock function (&lt;code&gt;mockOnSubmit&lt;/code&gt;) to simulate the onSubmit function, and simulates changing the text in the input field to a sample image link and presses the &lt;code&gt;Process&lt;/code&gt; button. It asserts that the &lt;code&gt;onSubmit&lt;/code&gt; function is called with the expected image URL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"handles image URL submission and displays the generated caption":&lt;/strong&gt;&lt;br&gt;
It mocks the Axios POST request to simulate generating a caption for an image URL. Simulates changing the text in the input field to a sample image link and pressing the "Process" button. It asserts that the generated caption is displayed in the expected format.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"shows camera if permissions are granted":&lt;/strong&gt;&lt;br&gt;
It spies on the &lt;code&gt;useCameraPermissions&lt;/code&gt; function to simulate that camera permissions are granted. Renders the App component. Simulates pressing the &lt;code&gt;Take Photo&lt;/code&gt; button, and finally, it asserts that the camera screen is displayed when permissions are granted.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"takes a picture and displays preview":&lt;/strong&gt;&lt;br&gt;
Again, it spies on &lt;code&gt;useCameraPermissions&lt;/code&gt; to simulate that camera permissions are granted and &lt;code&gt;takePictureAsync&lt;/code&gt; to mock taking a picture. Simulates pressing the &lt;code&gt;Take Photo&lt;/code&gt;button and then the capture button. It asserts that the captured image preview is displayed.&lt;/p&gt;

&lt;p&gt;These were just a few testing scenarios to get you started, but the possibilities are endless. Feel free to explore and add more scenarios that cover different aspects of your application. Think about a specific scenario or functionality you want to test. It could be related to user interactions, edge cases, or error handling.&lt;/p&gt;

&lt;p&gt;Full code is available for reference on GitHub &lt;a href="https://github.com/thisisgazzar/ai-image-captioner" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion:
&lt;/h2&gt;

&lt;p&gt;And there you have it – your very own Image Captioner is ready! But wait, what if we sprinkle a bit more magic? How about adding language translation feature to those captions? – there's always room for more creativity. You could explore more advanced models, tweak parameters, or even consider deploying your app to the cloud for broader accessibility.&lt;/p&gt;

&lt;p&gt;Catch you in the next one. Take care! 🚀✨&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>tutorial</category>
      <category>react</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Build a CRUD DApp using Solidity | Nextjs | Thirdweb | Tailwind CSS</title>
      <dc:creator>Mohamed Elgazzar</dc:creator>
      <pubDate>Sat, 04 Mar 2023 21:56:36 +0000</pubDate>
      <link>https://dev.to/thisisgazzar/build-a-crud-dapp-using-solidity-nextjs-thirdweb-tailwind-css-44m8</link>
      <guid>https://dev.to/thisisgazzar/build-a-crud-dapp-using-solidity-nextjs-thirdweb-tailwind-css-44m8</guid>
      <description>&lt;p&gt;Hey there, today we are going to be learning how to create the &lt;strong&gt;CRUD operations&lt;/strong&gt; in &lt;strong&gt;Web3&lt;/strong&gt; by building a simple Blog DApp. In this tutorial we will: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build a &lt;strong&gt;Solidity&lt;/strong&gt; smart contract that will hold the blog's content and allow users to interact with it.&lt;/li&gt;
&lt;li&gt;Deploy the smart contract to the Mumbai TestNet, and perform the Web3 interactions on the Frontend using &lt;strong&gt;Thirdweb&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Build the frontend using &lt;strong&gt;Nextjs&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Style our blog using &lt;strong&gt;Tailwind CSS&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By the end of that tutorial, you'll have a full-stack CRUD DApp, that you can build your Web3 knowledge upon, whether you are new to the technology, or just need to refresh your basics.&lt;/p&gt;

&lt;p&gt;Without further ado, let's dive right in and get started!&lt;/p&gt;

&lt;p&gt;Let's start by opening up the terminal and creating a new directory for our project&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mkdir Next3Blog &amp;amp;&amp;amp; cd Next3Blog&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here we are calling it &lt;strong&gt;Next3Blog&lt;/strong&gt; but you can call it whatever you want.&lt;/p&gt;

&lt;p&gt;After that, we are going to create a new Thirdweb project, that will contain our smart contract logic&lt;/p&gt;

&lt;p&gt;Run the following command&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npx thirdweb@latest create --contract&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It should prompt a few questions that will help setup the environment based on our needs&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9papl5hyslairduilo4u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9papl5hyslairduilo4u.png" alt=" " width="800" height="249"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I set the project name to &lt;strong&gt;web3&lt;/strong&gt;, picked &lt;strong&gt;Hardhat&lt;/strong&gt; as our development environment framework, set &lt;strong&gt;BlogContract&lt;/strong&gt; as the name of our smart contract, and finally, chose to initiate the project with an &lt;strong&gt;empty contract&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Navigate to the newly generated folder and take a look at the directory structure&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cd web3&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After navigating to the project folder, you will find the contracts directory which contains a single smart contract.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a Smart Contract using Solidity:
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Solidity&lt;/strong&gt; is a powerful high-level programming language. It's very similar to &lt;strong&gt;JavaScript&lt;/strong&gt;, but it's essentially designed and used to write smart contracts on the Ethereum blockchain.&lt;/p&gt;

&lt;p&gt;Open the contract file and copy the following code into it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;


contract BlogContract {
   struct Post {
        uint postId;
        address owner;
        string postContent;
        bool isDeleted;
    }

    mapping(uint =&amp;gt; address) blogOwners;
    Post[] private posts;
}

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

&lt;/div&gt;



&lt;p&gt;We start by specifying the compiler version for the smart contract.&lt;/p&gt;

&lt;p&gt;Then, we declare Post struct as a custom data type for our blog posts. It contains four variables, postId as uint which represents an unsigned (positive) integer, postContent as a string, isDeleted as a boolean.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mapping&lt;/code&gt; is a hash table that allows us to associate a key with a value, so in the above code we define a blogOwners mapping of a unit key, and address value.&lt;/p&gt;

&lt;p&gt;After that, we declare a private posts array of type Post. The private keyword makes the array inaccessible from outside the contract.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding posts:
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  function addPost(string memory postContent) external {
       uint postId = posts.length;
       address owner = msg.sender;
       posts.push(Post(postId, owner, postContent, false));
       blogOwners[postId] = owner;
   }

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

&lt;/div&gt;



&lt;p&gt;In Solidity, a function parameter must be declared with a specific data type since it's a typed language. &lt;/p&gt;

&lt;p&gt;In the above code, we are defining the addPost function, with a string parameter. &lt;code&gt;memory&lt;/code&gt; is used to store data temporarily during the execution of a function, and will be deleted from memory once the function returns.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;external&lt;/code&gt; makes the function visible from outside the contract only, and cannot be called from within the contract itself.&lt;/p&gt;

&lt;p&gt;We then assign a couple of variables, postId of type unit, and owner of type address. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;msg.sender&lt;/code&gt; refers to the address that called the function.&lt;/p&gt;

&lt;p&gt;After that, we use the Post struct to define the post variables and push it to the posts array. And finally, we map the postId to the blog owner address.&lt;/p&gt;

&lt;p&gt;In Solidity, &lt;code&gt;events&lt;/code&gt; are used as a way to notify external systems or contracts about specific actions that occur within a contract. &lt;/p&gt;

&lt;p&gt;Let's assign the &lt;strong&gt;AddPost&lt;/strong&gt; event that will serve as a notifier when a new post is registered.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;contract BlogContract {
   event AddPost(address owner, uint postId);
   ...
}

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

&lt;/div&gt;



&lt;p&gt;Now we add emit to the &lt;strong&gt;addPost&lt;/strong&gt; function to trigger the event.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function addPost(string memory postContent) external {
       ...
       emit AddPost(owner, postId);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deleting posts:
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function deletePost(uint postId) external {
       require(blogOwners[postId] == msg.sender, "You are not the owner of this post");
       posts[postId].isDeleted = true;
   }

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

&lt;/div&gt;



&lt;p&gt;Here we are defining a function that takes a single parameter postId of type uint, and then checking if the caller address is the owner of the post. &lt;code&gt;require&lt;/code&gt; checks for the validity of the condition and it will revert the transaction and display the error message that we set.&lt;/p&gt;

&lt;p&gt;Once data is written to the blockchain, &lt;strong&gt;it can’t be deleted&lt;/strong&gt; as it becomes a permanent part of the blockchain’s history. However, we can "soft-delete" it. Remember the variable isDeleted that we added above? We are initially assigning it to false, and we will simply modify it to be true, which will create an illusion of deleting it. &lt;/p&gt;

&lt;p&gt;Later on, when implementing the &lt;strong&gt;getPosts&lt;/strong&gt; function we will filter the data, and only return data with the isDeleted set to false.&lt;/p&gt;

&lt;p&gt;Let's now declare the DeletePost event&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
contract BlogContract {
   ...
   event DeletePost(uint postId, bool isDeleted);
   ...

   function deletePost(uint postId) external {
      ...
      emit DeletePost(postId, true);
   }

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Getting posts:
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function getPosts() external view returns (Post[] memory){
        Post[] memory temporary = new Post[](posts.length);
        uint counter = 0;
        for (uint i = 0; i &amp;lt; posts.length; i++) {
            if (posts[i].isDeleted == false) {
                temporary[counter] = posts[i];
                counter++;
            }
        }
        Post[] memory result = new Post[](counter);
        for (uint i = 0; i &amp;lt; counter; i++) {
            result[i] = temporary[i];
        }
        return result;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;code&gt;view&lt;/code&gt; function allows read-only access to the data stored in the contract and since it doesn't modify the state of the contract or blockchain, it doesn't require any transaction to be sent to the blockchain making it a lightweight operation.&lt;/p&gt;

&lt;p&gt;As I mentioned earlier, we are gonna loop through the posts array, and only return posts with the isDeleted set to false.&lt;/p&gt;

&lt;p&gt;First, we declare a temporary array of type Post, with a size equal to the length of the posts array.&lt;/p&gt;

&lt;p&gt;Note that when declaring an array with the memory keyword, you need to specify the size of the array because Solidity doesn't support dynamic array resizing in memory.&lt;/p&gt;

&lt;p&gt;Then we assign a counter variable that will track the number of the non "deleted" posts.&lt;/p&gt;

&lt;p&gt;Then we loop through the posts array and store the non deleted posts inside the temporary array.&lt;/p&gt;

&lt;p&gt;Since the temporary array may still have extra slots for the deleted posts, we need to declare another array of length counter to ensure that the final result array is of the exact size of the non-deleted posts.&lt;/p&gt;

&lt;p&gt;Now that we finished implementing the contract, we need to deploy it to the blockchain. In the project directory you will find &lt;code&gt;hardhat.config.js&lt;/code&gt;, this file contains all of our configuration settings of our development environment.&lt;/p&gt;

&lt;p&gt;Navigate to the file and copy the code below into it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = {
  solidity: {
    version: '0.8.9',
    defaultNetwork: 'mumbai',
    networks: {
      hardhat: {},
      mumbai: {
        url: 'https://rpc.ankr.com/polygon_mumbai',
        accounts: [`0x${process.env.PRIVATE_KEY}`]
      }
    },
    settings: {
      optimizer: {
        enabled: true,
        runs: 200,
      },
    },
  },
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we are specifying the settings for the Hardhat project.&lt;/p&gt;

&lt;p&gt;We declare the version of the compiler, the defaultNetwork as the &lt;strong&gt;Mumbai Testnet&lt;/strong&gt; and defining the network configurations, we specify the URL of the RPC endpoint "&lt;a href="https://rpc.ankr.com/polygon_mumbai" rel="noopener noreferrer"&gt;https://rpc.ankr.com/polygon_mumbai&lt;/a&gt;"  and the account to use for deployment.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;optimizer&lt;/code&gt; is a tool that tries to reduce the gas cost of a smart contract by optimizing its bytecode, and setting the optimizer to 200 means that it will run the optimizer for a maximum of 200 times. The more times the optimizer runs, the more aggressive it is in optimizing the bytecode, but it also takes longer to compile the contract.&lt;/p&gt;

&lt;p&gt;Now head to your browser and download the &lt;a href="https://metamask.io/download/" rel="noopener noreferrer"&gt;MetaMask wallet extension&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Follow the instructions to create a new wallet and don't forget to save the secret recovery phrase.&lt;/p&gt;

&lt;p&gt;After you successfully set up your wallet, head to the extension and add the Mumbai TestNet to your networks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkksp4trp4fx6kgpc5r32.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkksp4trp4fx6kgpc5r32.png" alt=" " width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Network name: Mumbai TestNet&lt;/li&gt;
&lt;li&gt;New RPC URL: &lt;a href="https://rpc.ankr.com/polygon_mumbai" rel="noopener noreferrer"&gt;https://rpc.ankr.com/polygon_mumbai&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Chain ID: 80001&lt;/li&gt;
&lt;li&gt;Currency symbol: MATIC&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now copy the private key as shown here. That will give access to the wallet account and enable us to deploy the contract using it&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8kp9leewehyy4817u9i5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8kp9leewehyy4817u9i5.png" alt=" " width="800" height="326"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For security purposes we need to add the private key into &lt;code&gt;.env&lt;/code&gt; file&lt;/p&gt;

&lt;p&gt;We need to install &lt;code&gt;dotenv&lt;/code&gt; to be able to load and manage the environment variables from the &lt;code&gt;.env&lt;/code&gt; file into the process environment.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install dotenv --save&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;When deploying the contract, it requires a certain amount of MATIC to cover the transaction fees.&lt;/p&gt;

&lt;p&gt;Let's now get some MATIC faucet (&lt;a href="https://faucet.polygon.technology/" rel="noopener noreferrer"&gt;https://faucet.polygon.technology/&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Head to &lt;a href="https://faucet.polygon.technology/" rel="noopener noreferrer"&gt;https://faucet.polygon.technology&lt;/a&gt; and copy your wallet address into the input, click submit, and you should get a small amount of MATIC in a few moments.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fypp5vltxhon93566m0yb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fypp5vltxhon93566m0yb.png" alt=" " width="800" height="161"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fekpkcu3vgl15kr3gahp6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fekpkcu3vgl15kr3gahp6.png" alt=" " width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This should be sufficient to deploy our contract.&lt;/p&gt;

&lt;p&gt;Now open your terminal and run the deployment command &lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm run deploy&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is a &lt;strong&gt;thirdweb&lt;/strong&gt; script that will detect any contract inside the directory and compile it, upload the ABI to IPFS and generate a deployment link.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy20mpelwuks1xrnig19k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy20mpelwuks1xrnig19k.png" alt=" " width="800" height="205"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open the link in your browser and click the deploy button to deploy the contract to the blockchain&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdbxxdct0k7g37atwnj5b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdbxxdct0k7g37atwnj5b.png" alt=" " width="800" height="355"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh2p4z67iupgkqfu9ux42.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh2p4z67iupgkqfu9ux42.png" alt=" " width="708" height="614"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thirdweb will generate a dashboard to manage and interact with the deployed contract conveniently. Copy the contract address and put it to the side now, we are gonna use it later when we move on to the Frontend part.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyr7ijgigr74lbyduub4t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyr7ijgigr74lbyduub4t.png" alt=" " width="750" height="201"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Navigate to &lt;strong&gt;Explorer&lt;/strong&gt; and play around with the contract functions&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3fxvjx6saa5nd0azv5k5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3fxvjx6saa5nd0azv5k5.png" alt=" " width="800" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Nextjs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Next.js&lt;/strong&gt; is an open-source React framework that provides server-side rendering, and makes it easier to build and optimize complex web applications.&lt;/p&gt;

&lt;p&gt;We'll start by setting up our development environment and create a Nextjs app&lt;/p&gt;

&lt;p&gt;Navigate to the root directory and copy the command below into your terminal&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npx create-next-app@latest client&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You will be prompted with a bunch of questions in the terminal&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw34rczw5ucrp9qpyp7id.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw34rczw5ucrp9qpyp7id.png" alt=" " width="444" height="46"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After it finishes installing the project dependencies, navigate to the project directory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tailwind CSS
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Tailwind CSS&lt;/strong&gt; is a utility-first CSS framework and a design system that provides you with pre-built classes to style your elements and create consistent and responsive web pages.&lt;/p&gt;

&lt;p&gt;So, let's say you have a button element and you want to change its background color to gray, you can simply add bg-gray-500 - Assigning the value as 500 means that the color is gonna have a mid-level shade.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setting up Tailwind CSS:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's first install the Tailwind CSS dependencies &lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install -D tailwindcss postcss autoprefixer&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;PostCSS and autoprefixer apply additional optimizations and ensure that the generated classes work on all browsers without worrying about the compatibility issues.&lt;/p&gt;

&lt;p&gt;Initialize Tailwind CSS in our project&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npx tailwindcss init -p&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That will generate two files npm &lt;code&gt;tailwind.config.js&lt;/code&gt; and &lt;code&gt;postcss.config.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Inside &lt;code&gt;tailwind.config.js&lt;/code&gt; copy the code below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = {
  content: [
    "./src/**/*.{js,jsx}",
  ],
  theme: {
    extend: {
      fontFamily: {
        openSans: ['Open Sans', 'sans-serif']
      }
    },
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we are adding the paths to all of the expected template files to contain Tailwind styles, and the font we're gonna use in the project.&lt;/p&gt;

&lt;p&gt;Then you navigate to &lt;strong&gt;./src/styles/globals.css&lt;/strong&gt; and add the Tailwind directives and the link for the font.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;600;700&amp;amp;display=swap');

@tailwind base;
@tailwind components;
@tailwind utilities;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we are ready to start building our UI&lt;/p&gt;

&lt;p&gt;Here is a closer look to the final view of what we are building&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1klub6bajfpvyctzuz72.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1klub6bajfpvyctzuz72.png" alt=" " width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the pages directory, you will find &lt;code&gt;index.js&lt;/code&gt;. This will be our main page.&lt;/p&gt;

&lt;p&gt;In the src directory create components directory, and inside of it create four new files &lt;code&gt;Navbar.js&lt;/code&gt;, &lt;code&gt;Form.js&lt;/code&gt;, &lt;code&gt;Post.js&lt;/code&gt;, and &lt;code&gt;index.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Add a &lt;strong&gt;utils&lt;/strong&gt; folder and inside of it create &lt;code&gt;index.js&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;By now the src directory tree should look like this&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft5migal6sj64ba8xo132.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft5migal6sj64ba8xo132.png" alt=" " width="112" height="105"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy the code below into ./pages/index.js&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default function App() {

  return (
    &amp;lt;div className="bg-[#eff2f5] flex flex-col min-h-screen"&amp;gt;



    &amp;lt;/div&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the tailwind classes that we are adding here are self-explanatory, we are simply setting the background color to #eff2f5, the display to flex, the flex direction to flex column, and the min height to 100vh.&lt;/p&gt;

&lt;p&gt;Let's install an additional package before we implement the Navbar&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm i react-identicons --save&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Identicons provide a visual representation to wallet addresses. They are typically generated using an algorithm that takes the wallet address as input and produces a unique image based on that input.&lt;/p&gt;

&lt;p&gt;Navigate to &lt;code&gt;Navbar.js&lt;/code&gt; and copy the following code into it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Identicon from 'react-identicons';
export default function Navbar() {
 return (
   &amp;lt;div className="bg-white"&amp;gt;
       &amp;lt;div className="px-5 py-2 flex items-center justify-between shadow-md"&amp;gt;
           &amp;lt;h2 className="font-openSans font-bold text-gray-600 font-medium"&amp;gt;
               Next3Blog
           &amp;lt;/h2&amp;gt;
           &amp;lt;div className="border border-[#c7cacd] text-gray-600 px-2 py-1 rounded-[12px] inline-flex items-center"&amp;gt;
               &amp;lt;div className="w-8 h-8 mr-2 rounded-full overflow-hidden border border-[#c7cacd] flex justify-center "&amp;gt;
                   &amp;lt;Identicon string={"0x34710CdeC3e80A174cb384870B3Ff2854d5556ce"} size={30}/&amp;gt;
               &amp;lt;/div&amp;gt;
               &amp;lt;h2 className="font-openSans text-black text-[12px]"&amp;gt;0x34710CdeC3e80A174cb384870B3Ff2854d5556ce&amp;lt;/h2&amp;gt;
           &amp;lt;/div&amp;gt;   
       &amp;lt;/div&amp;gt;
   &amp;lt;/div&amp;gt;
 )
}

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

&lt;/div&gt;



&lt;p&gt;Notice how we are using the font that we previously declared in the &lt;code&gt;tailwind.config.js&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;To save space, and make the UI more compact, let's shorten the wallet address that we are displaying on the Navbar. This is a convention in DApps to represent the address in a user-friendly way.&lt;/p&gt;

&lt;p&gt;Navigate to &lt;code&gt;./utils/index.js&lt;/code&gt; and add the following function&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const truncateAddress = (address) =&amp;gt; {
   return address.substring(0, 6) + '...' + address.substring(address.length - 4, address.length)
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This truncates the address to show the first 6 characters and the last 4 characters, with an ellipsis (...) in between.&lt;/p&gt;

&lt;p&gt;Let's import the function in &lt;code&gt;Navbar.js&lt;/code&gt; and call the function with the temporary address.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...               
&amp;lt;h2 className="font-openSans text-black text-[12px]"&amp;gt;{truncateAddress(address)}&amp;lt;/h2&amp;gt;
...

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

&lt;/div&gt;



&lt;p&gt;Next, navigate to &lt;code&gt;Form.js&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 Identicon from 'react-identicons';
export default function Form() {
 return (
   &amp;lt;form className="lg:w-1/2 flex flex-col w-full h-full bg-white overflow-hidden mb-[50px] shadow-md rounded-[8px] py-5 px-10 box-border"&amp;gt;
       &amp;lt;div className="w-full inline-flex justify-between items-center mb-4"&amp;gt;
       &amp;lt;div className="w-12 h-12 rounded-full overflow-hidden border border-[#c7cacd] flex justify-center "&amp;gt;
           &amp;lt;Identicon string={"0x34710CdeC3e80A174cb384870B3Ff2854d5556ce"} size={45}/&amp;gt;
       &amp;lt;/div&amp;gt;
       &amp;lt;div className="w-4/5 lg:w-[90%]"&amp;gt;
           &amp;lt;input type="text" id="post" className="font-openSans w-full p-3 text-md border rounded-[22px] focus:outline-none focus:shadow-outline" placeholder="Share Your Thoughts and Ideas!" /&amp;gt;
       &amp;lt;/div&amp;gt;
       &amp;lt;/div&amp;gt;
       &amp;lt;div className="w-full justify-center items-center"&amp;gt;
       &amp;lt;button className="w-full bg-[#1974E7] px-2 py-2 rounded-[6px] flex justify-center cursor-pointer disabled:opacity-50 disabled:cursor-default" type='submit'&amp;gt;
           &amp;lt;h2 className='font-openSans text-white transition'&amp;gt;Publish&amp;lt;/h2&amp;gt;
       &amp;lt;/button&amp;gt;
       &amp;lt;/div&amp;gt;
   &amp;lt;/form&amp;gt;
 )
}

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;w-4/5&lt;/strong&gt;: Sets the width to 75%&lt;br&gt;
&lt;strong&gt;lg:w-[90%]&lt;/strong&gt;: Sets the width to 90% on large screens&lt;/p&gt;

&lt;p&gt;Navigate to &lt;code&gt;Post.js&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 Identicon from 'react-identicons';
import { truncateAddress } from '@/utils';


export default function Post() {
 return (
   &amp;lt;div className="lg:w-1/2 flex flex-col w-full h-full bg-white overflow-hidden mb-6 shadow-md rounded-[8px] pt-2 pb-5 px-6 box-border"&amp;gt;
       &amp;lt;div className="w-full inline-flex justify-between items-center mb-4"&amp;gt;
         &amp;lt;div className="inline-flex items-center"&amp;gt;
           &amp;lt;div className="w-[40px] h-[40px] flex justify-center rounded-full overflow-hidden flex-shrink-0 border border-[#c7cacd]"&amp;gt;
             &amp;lt;Identicon string={"0x34710CdeC3e80A174cb384870B3Ff2854d5556ce"} size={35} /&amp;gt;
           &amp;lt;/div&amp;gt;
           &amp;lt;div className="flex-1 pl-2"&amp;gt;
             &amp;lt;h2 className="font-openSans text-black mb-1"&amp;gt;{truncateAddress("0x34710CdeC3e80A174cb384870B3Ff2854d5556ce")}&amp;lt;/h2&amp;gt;
           &amp;lt;/div&amp;gt;
         &amp;lt;/div&amp;gt;
           &amp;lt;button className="w-[10px] cursor-pointer"&amp;gt;
             &amp;lt;svg className="fill-current w-3 h-3" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="122.878px" height="122.88px" viewBox="0 0 122.878 122.88" enableBackground="new 0 0 122.878 122.88" xml-space="preserve"&amp;gt;
               &amp;lt;g&amp;gt;
                 &amp;lt;path d="M1.426,8.313c-1.901-1.901-1.901-4.984,0-6.886c1.901-1.902,4.984-1.902,6.886,0l53.127,53.127l53.127-53.127 c1.901-1.902,4.984-1.902,6.887,0c1.901,1.901,1.901,4.985,0,6.886L68.324,61.439l53.128,53.128c1.901,1.901,1.901,4.984,0,6.886 c-1.902,1.902-4.985,1.902-6.887,0L61.438,68.326L8.312,121.453c-1.901,1.902-4.984,1.902-6.886,0 c-1.901-1.901-1.901-4.984,0-6.886l53.127-53.128L1.426,8.313L1.426,8.313z"&amp;gt;&amp;lt;/path&amp;gt;
               &amp;lt;/g&amp;gt;
             &amp;lt;/svg&amp;gt;
           &amp;lt;/button&amp;gt;
       &amp;lt;/div&amp;gt;
       &amp;lt;div className="w-full justify-center items-center"&amp;gt;
         &amp;lt;p className='font-openSans'&amp;gt;Sample Blog post&amp;lt;/p&amp;gt;
       &amp;lt;/div&amp;gt;
     &amp;lt;/div&amp;gt;
 )
}

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

&lt;/div&gt;



&lt;p&gt;Now to better organize our components export them in the &lt;strong&gt;./components/index.js&lt;/strong&gt; file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export { default as Navbar } from './Navbar';
export { default as Form } from './Form';
export { default as Post } from './Post';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, we import our components to our main page &lt;strong&gt;./pages/index.js&lt;/strong&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 { Navbar, Form, Post } from "@/components";
...
 return (
   &amp;lt;div className="bg-[#eff2f5] flex flex-col min-h-screen"&amp;gt;
     &amp;lt;Navbar /&amp;gt;
     &amp;lt;div className="pt-12 pb-6 flex flex-col items-center justify-center"&amp;gt;
       &amp;lt;Form /&amp;gt;
       &amp;lt;Post /&amp;gt;
     &amp;lt;/div&amp;gt;
   &amp;lt;/div&amp;gt;
 )
}

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Thirdweb Integrations:
&lt;/h2&gt;

&lt;p&gt;Now that we are done creating the base UI for our app. Let's start the Web3 integrations to be able to interact with our contract&lt;/p&gt;

&lt;p&gt;Install the dependencies&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm i @thirdweb-dev/sdk @thirdweb-dev/react --save&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Navigate to &lt;strong&gt;./pages/_app.js&lt;/strong&gt; and copy the following code into it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Head from 'next/head';
import { ChainId, ThirdwebProvider } from '@thirdweb-dev/react';
import '@/styles/globals.css'


export default function App({ Component, pageProps }) {
 return (
   &amp;lt;ThirdwebProvider network={ChainId.Mumbai}&amp;gt;
     &amp;lt;Head&amp;gt;
       &amp;lt;title&amp;gt;Next3Blog&amp;lt;/title&amp;gt;
     &amp;lt;/Head&amp;gt;
     &amp;lt;Component {...pageProps} /&amp;gt;
   &amp;lt;/ThirdwebProvider&amp;gt;
 )
}

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

&lt;/div&gt;



&lt;p&gt;Here we are wrapping the app with the Thirdweb provider, and setting the network to the Mumbai chain id.&lt;/p&gt;

&lt;p&gt;Inside &lt;strong&gt;./pages/index.js&lt;/strong&gt; copy the following code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useMetamask, useAddress } from "@thirdweb-dev/react";
export default function App() {
 const connect = useMetamask();
 const address = useAddress();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We import a couple of hooks provided by Thirdweb, we're gonna need a &lt;strong&gt;useMetamask&lt;/strong&gt; to connect the app to Metamask wallet and &lt;strong&gt;useAddress&lt;/strong&gt; that gets the connected address&lt;/p&gt;

&lt;p&gt;Then we pass both hooks to the &lt;strong&gt;Navbar&lt;/strong&gt; component and address to the &lt;strong&gt;Form&lt;/strong&gt; and &lt;strong&gt;Post&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
&amp;lt;div className="bg-[#eff2f5] flex flex-col min-h-screen"&amp;gt;
 &amp;lt;Navbar
   connect={connect}
   address={address}
 /&amp;gt;
 &amp;lt;div className="pt-12 pb-6 flex flex-col items-center justify-center"&amp;gt;
   &amp;lt;Form
     address={address}
   /&amp;gt;
   &amp;lt;Post
     address={address}
   /&amp;gt;
 &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
...

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

&lt;/div&gt;



&lt;p&gt;Let's implement the connect wallet functionality in the &lt;strong&gt;Navbar&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default function Navbar({ connect, address }) {
 return (
   &amp;lt;div className="bg-white"&amp;gt;
       ...
       { address ?
           &amp;lt;div className="border border-[#c7cacd] text-gray-600 px-2 py-1 rounded-[12px] inline-flex items-center"&amp;gt;
               &amp;lt;div className="w-8 h-8 mr-2 rounded-full overflow-hidden border border-[#c7cacd] flex justify-center "&amp;gt;
                   &amp;lt;Identicon string={address} size={30}/&amp;gt;
               &amp;lt;/div&amp;gt;
               &amp;lt;h2 className="font-openSans text-black text-[12px]"&amp;gt;{truncateAddress(address)}&amp;lt;/h2&amp;gt;
           &amp;lt;/div&amp;gt; :
           &amp;lt;button className="group/item border border-[#c7cacd] text-gray-600 px-2 py-1 rounded-[12px] inline-flex items-center cursor-pointer hover:bg-[#1974E7] hover:text-white transition"
               onClick={() =&amp;gt; connect()}
           &amp;gt;
               &amp;lt;h2 className='font-openSans group-hover/item:text-white text-[#1974E7] transition'&amp;gt;Connect Wallet&amp;lt;/h2&amp;gt;
           &amp;lt;/button&amp;gt;
       }
       ...
   &amp;lt;/div&amp;gt;
 )
}

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

&lt;/div&gt;



&lt;p&gt;Here we are doing conditional rendering, so we show the address if there is a connected address, or else show the connect button&lt;/p&gt;

&lt;p&gt;Back to &lt;code&gt;index.js&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We import &lt;strong&gt;useContract&lt;/strong&gt; to be able to connect to our contract and pass our smart contract address to it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { ..., useContract } from "@thirdweb-dev/react";
...
export default function App() {
...
const { contract } = useContract("0x1e55A7D8c854c239cD30EA737700D1C7d7273395");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's do our first contract call&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

...
 const [posts, setPosts] = useState([]);
...
const getPosts = async () =&amp;gt; {
   try {
     const posts = await contract.call('getPosts');
     const parsedPosts = posts.map((post, i) =&amp;gt; ({
       owner: post.owner,
       postContent: post.postContent,
       id: post.postId.toNumber()
     }));
     setPosts(parsedPosts);
   }
   catch (err) {
     console.error("contract call failure", err);
   }
 }

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Thirdweb&lt;/strong&gt; makes it extremely simple to integrate our smart contract functions.&lt;br&gt;
Here we are calling the &lt;strong&gt;getPosts&lt;/strong&gt; function and then parsing through the returned posts array to get the values that we need. If you haven’t played around on Thirdweb dashboard and created a post, this should be returning an empty array.&lt;/p&gt;

&lt;p&gt;Then we call the function inside useEffect to run whenever the component mounts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; useEffect(() =&amp;gt; {
   if(contract) getPosts();
 }, [address, contract]);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;we check if the contract value exists before calling &lt;strong&gt;getPosts&lt;/strong&gt;, and re-runs whenever the address or contract values is updated.&lt;/p&gt;

&lt;p&gt;Next, we map over the posts array to return a list of Post components.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{posts.map(post =&amp;gt;
         &amp;lt;Post
           key={post.id}
           id={post.id}
           owner={post.owner}
           address={address}
           postContent={post.postContent}
         /&amp;gt;)
       }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before we implement the create post functionality we need to keep track of the form input value, let’s declare a new useState variable and pass it down to the Form component&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;... 
const [text, setText] = useState('');
...
&amp;lt;Form
         address={address}
         setText={setText}
         text={text}
         buttonText={buttonText}
       /&amp;gt;
...

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

&lt;/div&gt;



&lt;p&gt;In the Form component we set up the event listener that is triggered whenever the user types something into the input field&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default function Form({ setText, text }) {
   return (
     &amp;lt;form className="lg:w-1/2 flex flex-col w-full h-full bg-white overflow-hidden mb-[50px] shadow-md rounded-[8px] py-5 px-10 box-border"&amp;gt;
          ...


         &amp;lt;div className="w-4/5 lg:w-[90%]"&amp;gt;
             &amp;lt;input type="text" id="post" className="font-openSans w-full p-3 text-md border rounded-[22px] focus:outline-none focus:shadow-outline" placeholder="Share Your Thoughts and Ideas!"
                 value={text}
                 onChange={e=&amp;gt;setText(e.target.value)}
             /&amp;gt;
         &amp;lt;/div&amp;gt;

         ...
      &amp;lt;/form&amp;gt;
   )
 }

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

&lt;/div&gt;



&lt;p&gt;Navigate back to &lt;code&gt;index.js&lt;/code&gt; and let’s implement publishPost function&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; const [publishLoading, setPublishLoading] = useState(false);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We declare &lt;strong&gt;publishLoading&lt;/strong&gt; state variable to track the loading state while executing the function&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const publishPost = async (text) =&amp;gt; {
   if(text.length &amp;gt; 0 &amp;amp;&amp;amp; contract){
     try {
       setPublishLoading(true);
       const data = await contract.call('addPost', text);
       if(data.receipt.status === 1){
         getPosts();
         setText('');
       }
       return data;
     } catch (err) {
       console.error("contract call failure", err);
     } finally {
       setPublishLoading(false);
     }
   }
 }

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

&lt;/div&gt;



&lt;p&gt;Here we are calling the &lt;strong&gt;addPost&lt;/strong&gt; function and passing the input text to it, after checking if the text input is not empty and the contract exists. &lt;/p&gt;

&lt;p&gt;If the transaction was successful, we call the &lt;strong&gt;getPosts&lt;/strong&gt; function, and clear out the input field.&lt;/p&gt;

&lt;p&gt;Next, we pass the function down to the &lt;strong&gt;Form&lt;/strong&gt; component&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
&amp;lt;Form
         ...
         publishPost={publishPost}
         ...
       /&amp;gt;
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we update the Form component to trigger the &lt;strong&gt;publishPost&lt;/strong&gt; on submit&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default function Form({ ... text, publishPost }) {
   return (
     &amp;lt;form className="lg:w-1/2 flex flex-col w-full h-full bg-white overflow-hidden mb-[50px] shadow-md rounded-[8px] py-5 px-10 box-border" onSubmit={() =&amp;gt; publishPost(text)}&amp;gt;
          ...
      &amp;lt;/form&amp;gt;
   )
 }

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

&lt;/div&gt;



&lt;p&gt;Now we implement the &lt;strong&gt;deletePost&lt;/strong&gt; function&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;onst deletePost = async (id) =&amp;gt; {
   try {
     const data = await contract.call('deletePost', id);
     if(data.receipt.status === 1){
       getPosts();
     }
     return data;
   } catch (err) {
     console.error("contract call failure", err);
   }

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

&lt;/div&gt;



&lt;p&gt;Similar to the functions we implemented earlier, we call the deletePost function and passing the post id to it, and pass it down to Post component&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{posts.map(post =&amp;gt;
         &amp;lt;Post
           ...
           deletePost={deletePost}
         /&amp;gt;)
       }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update &lt;code&gt;Post.js&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;export default function Post({ ... id, owner, address, deletePost }) {
 return (
   &amp;lt;div className="lg:w-1/2 flex flex-col w-full h-full bg-white overflow-hidden mb-6 shadow-md rounded-[8px] pt-2 pb-5 px-6 box-border"&amp;gt;
               { owner === address &amp;amp;&amp;amp;
           &amp;lt;button className="w-[10px] cursor-pointer" onClick={() =&amp;gt; deletePost(id)}&amp;gt;
             &amp;lt;svg className="fill-current w-3 h-3" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="122.878px" height="122.88px" viewBox="0 0 122.878 122.88" enableBackground="new 0 0 122.878 122.88" xml-space="preserve"&amp;gt;
               &amp;lt;g&amp;gt;
                 &amp;lt;path d="M1.426,8.313c-1.901-1.901-1.901-4.984,0-6.886c1.901-1.902,4.984-1.902,6.886,0l53.127,53.127l53.127-53.127 c1.901-1.902,4.984-1.902,6.887,0c1.901,1.901,1.901,4.985,0,6.886L68.324,61.439l53.128,53.128c1.901,1.901,1.901,4.984,0,6.886 c-1.902,1.902-4.985,1.902-6.887,0L61.438,68.326L8.312,121.453c-1.901,1.902-4.984,1.902-6.886,0 c-1.901-1.901-1.901-4.984,0-6.886l53.127-53.128L1.426,8.313L1.426,8.313z"&amp;gt;&amp;lt;/path&amp;gt;
               &amp;lt;/g&amp;gt;
             &amp;lt;/svg&amp;gt;
           &amp;lt;/button&amp;gt;
         }      


     &amp;lt;/div&amp;gt;
 )
}

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

&lt;/div&gt;



&lt;p&gt;Here we are checking if the owner of the post has the same address that is connected to the app, and if so showing the close button.&lt;/p&gt;

&lt;p&gt;One final thing that is left, let's add some conditional styles and text to the submit button. We need to disable it if the app is not connected to the wallet or not connected to the Mumbai network, or if the publishLoading state variable is true.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;index.js&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;... 
const buttonText = !address ? "Connect Wallet" : chainId !== ChainId.Mumbai ? "Connect to the Mumbai TestNet" : publishLoading ? "Loading..." : "Publish";
 const buttonDisabled = !address || chainId !== ChainId.Mumbai || publishLoading;
...

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

&lt;/div&gt;



&lt;p&gt;Path both variables to &lt;strong&gt;Form&lt;/strong&gt; component&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Form
        ...
         buttonDisabled={buttonDisabled}
         buttonText={buttonText}
       /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update &lt;code&gt;Form.js&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;export default function Form({ ... buttonText, buttonDisabled }) {
 return (
   &amp;lt;form className="lg:w-1/2 flex flex-col w-full h-full bg-white overflow-hidden mb-[50px] shadow-md rounded-[8px] py-5 px-10 box-border" onSubmit={() =&amp;gt; publishPost(text)}&amp;gt;


       ...


       &amp;lt;div className="w-full justify-center items-center"&amp;gt;
       &amp;lt;button className="w-full bg-[#1974E7] px-2 py-2 rounded-[6px] flex justify-center cursor-pointer disabled:opacity-50 disabled:cursor-default" type='submit' disabled={buttonDisabled} onClick={() =&amp;gt; publishPost(text)}&amp;gt;
           &amp;lt;h2 className='font-openSans text-white transition'&amp;gt;{buttonText}&amp;lt;/h2&amp;gt;
       &amp;lt;/button&amp;gt;
       &amp;lt;/div&amp;gt;


   &amp;lt;/form&amp;gt;
 )
}

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

&lt;/div&gt;



&lt;p&gt;Notice how we are using the Tailwind's &lt;code&gt;disabled:&lt;/code&gt; modifier to customize the disabled style.&lt;/p&gt;

&lt;p&gt;And that's a wrap!&lt;/p&gt;

&lt;p&gt;Full code can be found in the github repo &lt;a href="https://github.com/thisisgazzar/next3blog" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion:
&lt;/h2&gt;

&lt;p&gt;Whew, you made it to the end of the tutorial! You now have a solid understanding of how to build a full-stack dApp using some of the coolest and trendiest technologies out there. To take your learning further, you can add the &lt;strong&gt;update&lt;/strong&gt; functionality to the post content, &lt;strong&gt;loading&lt;/strong&gt; state for &lt;strong&gt;getPosts&lt;/strong&gt;, and you can also use packages like &lt;strong&gt;Draft.js&lt;/strong&gt; to add a customizable text editor instead of the simple input that we implemented. Additionally, you can implement user profile &lt;strong&gt;routing&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for following along. Have a good one!&lt;/p&gt;

</description>
      <category>web3</category>
      <category>nextjs</category>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Building a Form using React Native and Animated API with Unit testing</title>
      <dc:creator>Mohamed Elgazzar</dc:creator>
      <pubDate>Mon, 16 Jan 2023 11:37:20 +0000</pubDate>
      <link>https://dev.to/thisisgazzar/building-a-form-using-react-native-and-animated-api-with-unit-testing-4cc3</link>
      <guid>https://dev.to/thisisgazzar/building-a-form-using-react-native-and-animated-api-with-unit-testing-4cc3</guid>
      <description>&lt;p&gt;&lt;strong&gt;React Native&lt;/strong&gt; is a cross-platform mobile development framework based on JavaScript and Node.js. It allows you to build mobile applications for &lt;strong&gt;Android&lt;/strong&gt; and &lt;strong&gt;iOS&lt;/strong&gt; without writing code for each platform.&lt;/p&gt;

&lt;p&gt;In this article, I'm going to walk you through building a simple form using &lt;strong&gt;Formik&lt;/strong&gt;, perform some basic &lt;strong&gt;validations&lt;/strong&gt; and &lt;strong&gt;unit testing&lt;/strong&gt;, and then add a little bit of animations using the &lt;strong&gt;Animated API&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We are going to use &lt;strong&gt;Expo&lt;/strong&gt; to set up our development environment, so let's first install &lt;strong&gt;Expo CLI&lt;/strong&gt; globally.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install -g expo-cli&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now let's create an Expo project&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npx create-expo-app react-native-formik&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once the installation finishes, you can run the app using the following command&lt;/p&gt;

&lt;p&gt;&lt;code&gt;expo start&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You can view the app using the &lt;strong&gt;Xcode&lt;/strong&gt; or Android Studio &lt;strong&gt;simulator&lt;/strong&gt;, or scan the &lt;strong&gt;QR code&lt;/strong&gt; shown on your terminal after you download the &lt;strong&gt;Expo Go app&lt;/strong&gt; from the App Store or Google play, to be able to run the app on your mobile phone.&lt;/p&gt;

&lt;p&gt;Let's now do some coding!&lt;/p&gt;

&lt;p&gt;We will start by installing &lt;strong&gt;Formik&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install formik --save&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Formik&lt;/strong&gt; is a lightweight form library for &lt;strong&gt;ReactJS&lt;/strong&gt; and &lt;strong&gt;React Native&lt;/strong&gt;. It provides you with a reusable form component which reduces a lot of boilerplate code and simplifies handling the three most annoying parts in the form building process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Getting values in and out of form state &lt;/li&gt;
&lt;li&gt;Validation and error messages &lt;/li&gt;
&lt;li&gt;Handling form submission&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Copy the code below into &lt;code&gt;App.js&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 React from "react";
import {
  TextInput,
  Pressable,
  Text,
  View,
  StyleSheet
} from "react-native";
import { Formik } from "formik";

export default function App() {
  return (
    &amp;lt;View style={styles.container}&amp;gt;
      &amp;lt;Formik
        initialValues={{ username: "", email: "" }}
        onSubmit={(values) =&amp;gt; console.log(values)}
      &amp;gt;
        {({
          handleSubmit,
          handleChange,
          values
        }) =&amp;gt; {
          return (
            &amp;lt;View&amp;gt;
              &amp;lt;TextInput
                onChangeText={handleChange("username")}
                value={values.username}
                placeholder="username"
                style={styles.input}
              /&amp;gt;

              &amp;lt;TextInput
                onChangeText={handleChange("email")}
                value={values.email}
                placeholder="email"
                style={styles.input}
              /&amp;gt;

              &amp;lt;View&amp;gt;
                &amp;lt;Pressable
                  style={[styles.pressable, { transform: [{ scale }] }]}
                  onPress={handleSubmit}
                  onPressIn={onPressIn}
                  testID="button"
                  onPressOut={onPressOut}
                &amp;gt;
                  &amp;lt;Text style={styles.buttonText}&amp;gt;submit&amp;lt;/Text&amp;gt;
                &amp;lt;/Pressable&amp;gt;
              &amp;lt;/View&amp;gt;
            &amp;lt;/View&amp;gt;
          );
        }}
      &amp;lt;/Formik&amp;gt;
    &amp;lt;/View&amp;gt;
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center",
  },
  input: {
    width: 250,
    height: 40,
    marginBottom: 5,
    borderWidth: 2,
    padding: 5,
    borderColor: "#000",
  },
  pressable: {
    width: 250,
    height: 40,
    alignItems: "center",
    justifyContent: "center",
    backgroundColor: "#000",
  },
  text: {
    color: "#000",
  },
  buttonText: {
    color: "#fff",
  },
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx4tnc827af1w37ljmg0f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx4tnc827af1w37ljmg0f.png" alt=" " width="624" height="1354"&gt;&lt;/a&gt;&lt;br&gt;
Here we are setting the Formik component&lt;/p&gt;

&lt;p&gt;Notice that &lt;strong&gt;React Native&lt;/strong&gt; does not provide a form component, so we are setting Formik and inside of it we are importing View as a wrapper for our form components, you can think of &lt;strong&gt;View&lt;/strong&gt; as the equivalent of &lt;strong&gt;div&lt;/strong&gt; in web development.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Button&lt;/strong&gt; component supports a minimal level of customization and has no style property, so we are using &lt;strong&gt;Pressable&lt;/strong&gt; as an alternative to customize our own button.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;handleSubmit&lt;/strong&gt; is auto generated from Formik to handle validation and submission.&lt;/p&gt;

&lt;p&gt;We provide the Formik component with the &lt;strong&gt;initialValues&lt;/strong&gt; object of our form. Here we are just assigning username and email.&lt;/p&gt;

&lt;p&gt;Then we pass the &lt;strong&gt;handleChange&lt;/strong&gt; method provided by Formik into the &lt;strong&gt;onChangeText&lt;/strong&gt; callback in the &lt;strong&gt;TextField&lt;/strong&gt; components with their corresponding key in the initialValues object.&lt;/p&gt;

&lt;p&gt;And finally, we pass &lt;strong&gt;onSubmit&lt;/strong&gt; as a prop into the Formik component, and here we are just printing the values to the console.&lt;/p&gt;
&lt;h2&gt;
  
  
  Validation:
&lt;/h2&gt;

&lt;p&gt;Formik comes with built-in support for &lt;strong&gt;Yup&lt;/strong&gt; which is a JavaScript schema builder for value parsing and validation.&lt;/p&gt;

&lt;p&gt;Let's install Yup&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install yup --save&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now we import Yup and create our validation schema&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...

import * as Yup from "yup";

const Schema = Yup.object().shape({
  username: Yup.string().required("username is required"),
  email: Yup.string().email().required("email is required"),
});

...


 &amp;lt;Formik
        initialValues={{ username: "", email: "" }}
        validationSchema={Schema}
        onSubmit={(values) =&amp;gt; console.log(values)}
 &amp;gt;
        {({
          handleSubmit,
          handleChange,
          values,
          errors,
          touched
        }) =&amp;gt; {

...

{errors.username &amp;amp;&amp;amp; touched.username &amp;amp;&amp;amp; (
&amp;lt;Text style={styles.text}&amp;gt;{errors.username}&amp;lt;/Text&amp;gt;)}{errors.email &amp;amp;&amp;amp; touched.email &amp;amp;&amp;amp; (
&amp;lt;Text style={styles.text}&amp;gt;{errors.email}&amp;lt;/Text&amp;gt;)}

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

&lt;/div&gt;



&lt;p&gt;Here we are marking username and email as required fields, and adding the email method which uses a regex under the hood to validate the email format. Then we pass the schema into Formik's Yup config prop &lt;strong&gt;validationSchema&lt;/strong&gt;, which will manage and map the error messages we set in the schema.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foe9ffxse33e3ibl4807x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foe9ffxse33e3ibl4807x.png" alt=" " width="624" height="1354"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Unit Testing:
&lt;/h2&gt;

&lt;p&gt;Unit testing is the practice of testing small pieces of code on their own, which makes it easier to track, control and refactor the code without any disruption.&lt;br&gt;
We will use &lt;strong&gt;Jest&lt;/strong&gt; as our test runner and &lt;strong&gt;Testing Library&lt;/strong&gt; for providing the testing utilities needed for catching our components to perform actions upon them.&lt;/p&gt;

&lt;p&gt;Let's starts by installing Expo's compatible version of Jest&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install jest-expo jest --save-dev&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then we need to do some configurations in &lt;code&gt;package.json&lt;/code&gt; and add the testing script&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    ...  

    "scripts": {
      ...
      "test": "jest"
    },
    "jest": {
      "preset": "jest-expo",
      "transformIgnorePatterns": [
        "node_modules/(?!((jest-)?react-native|@react-native(-community)?)|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base|react-native-svg)"
      ],
      "collectCoverage": true,
      "collectCoverageFrom": [
        "**/*.{js,jsx}",
        "!**/coverage/**",
        "!**/node_modules/**",
        "!**/babel.config.js",
        "!**/jest.setup.js"
      ]
    },
    ...
  }

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

&lt;/div&gt;



&lt;p&gt;For more info about Jest configurations, visit the official docs &lt;a href="https://docs.expo.dev/guides/testing-with-jest/" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create a new folder &lt;code&gt;__tests__&lt;/code&gt; in the root directory and inside of it create &lt;code&gt;App.test.js&lt;/code&gt; which will include our tests.&lt;/p&gt;

&lt;p&gt;Let's perform our first test case&lt;/p&gt;

&lt;p&gt;Copy the code below into &lt;code&gt;App.test.js&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 React from "react";
import { render, fireEvent, waitFor } from "@testing-library/react-native";
import App from "../App";

describe("Form Validations", () =&amp;gt; {
  it("does not show error messages when required values are fullfilled", async () =&amp;gt; {

    });
  });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;describe&lt;/strong&gt; is used to organize a set of related test scenarios. Here, we are &lt;strong&gt;describing&lt;/strong&gt; our testing block as "Form Validations" and it will contain all the positive and negative scenarios for the validations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;it&lt;/strong&gt; is the method where we perform each individual test.&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 from "react";
import { render, fireEvent, waitFor } from "@testing-library/react-native";
import App from "../App";

describe("Form Validations", () =&amp;gt; {
  it("does not show error messages when required values are fullfilled", async () =&amp;gt; {
    const { getByPlaceholderText, queryByText, getByTestId } = render(&amp;lt;App /&amp;gt;);

    let usernameInput = getByPlaceholderText("username");
    let emailInput = getByPlaceholderText("email");
    let submitButton = getByTestId("button");

    fireEvent.changeText(usernameInput, "Mohamed");
    fireEvent.changeText(emailInput, "mohamed@email.com");

    await waitFor(() =&amp;gt; {
      fireEvent.press(submitButton);
    });

    await waitFor(() =&amp;gt; {
      expect(queryByText("username is required")).toBeNull();
      expect(queryByText("email is required")).toBeNull();
    });
  });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our first scenario is where the user has filled in all the form inputs, so here we are assuming that the required warning does not show up.&lt;/p&gt;

&lt;p&gt;We are rendering our form and then using the testing library special queries to get the components we need to perform the test on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;getByPlaceholderText&lt;/strong&gt; searches for the input that holds the matching placeholder we provide.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;getByTestId&lt;/strong&gt; gets the component that holds the matching &lt;strong&gt;testID&lt;/strong&gt;, so let’s get back to App.js and assign a testID to the &lt;strong&gt;Pressable&lt;/strong&gt; component&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;fireEvent&lt;/strong&gt; is used to invoke a given event handler, so we are using it here to change the input texts and then pressing the submit button that we got above. And we are using waitFor to wait until the press event is fulfilled.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
it("shows error messages when required values are not fullfilled", async () =&amp;gt; {
    const { getByPlaceholderText, queryByText, getByTestId } = render(&amp;lt;App /&amp;gt;);

    let usernameInput = getByPlaceholderText("username");
    let emailInput = getByPlaceholderText("email");
    let submitButton = getByTestId("button");

    fireEvent.changeText(usernameInput, "");
    fireEvent.changeText(emailInput, "");

    await waitFor(() =&amp;gt; {
      fireEvent.press(submitButton);
    });

    await waitFor(() =&amp;gt; {
      expect(queryByText("username is required")).toBeTruthy();
      expect(queryByText("email is required")).toBeTruthy();
    });
  });
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second scenario is where the user has not filled the form inputs, so we expect the required errors to show up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;toBeNull&lt;/strong&gt; and &lt;strong&gt;toBeTruthy&lt;/strong&gt; are Jest expectations to assume whether a specific component exists or not.&lt;/p&gt;

&lt;p&gt;You can find more info about Jest expectation &lt;a href="https://jestjs.io/docs/expect" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You have probably noticed how we repeatedly rendered the App component and defined the same variables in both tests, so to avoid the redundancy we use Jest's &lt;strong&gt;beforeEach&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
describe("Form Validations", () =&amp;gt; {
  let getByPlaceholderText,
    queryByText,
    getByTestId,
    usernameInput,
    emailInput,
    submitButton;
  beforeEach(() =&amp;gt; {
    ({ getByPlaceholderText, queryAllByText, queryByText, getByTestId } =
      render(&amp;lt;App /&amp;gt;));
    usernameInput = getByPlaceholderText("username");
    emailInput = getByPlaceholderText("email");
    submitButton = getByTestId("button");
  });

  it("does not show error messages when required values are fullfilled", async () =&amp;gt; {
    fireEvent.changeText(usernameInput, "Mohamed");
    fireEvent.changeText(emailInput, "mohamed@email.com");

    await waitFor(() =&amp;gt; {
      fireEvent.press(submitButton);
    });

    await waitFor(() =&amp;gt; {
      expect(queryByText("username is required")).toBeNull();
      expect(queryByText("email is required")).toBeNull();
    });
  });

  it("shows error messages when required values are not fullfilled", async () =&amp;gt; {
    fireEvent.changeText(usernameInput, "");
    fireEvent.changeText(emailInput, "");

    await waitFor(() =&amp;gt; {
      fireEvent.press(submitButton);
    });

    await waitFor(() =&amp;gt; {
      expect(queryByText("username is required")).toBeTruthy();
      expect(queryByText("email is required")).toBeTruthy();
    });
  });
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we perform the couple left scenarios where we expect whether a valid email is provided or not.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  it("does not show error message when email is valid", async () =&amp;gt; {
    fireEvent.changeText(usernameInput, "Mohamed");
    fireEvent.changeText(emailInput, "mohamed@email.com");

    await waitFor(() =&amp;gt; {
      fireEvent.press(submitButton);
    });

    await waitFor(() =&amp;gt; {
      expect(queryByText("email must be a valid email")).toBeNull();
    });
  });

  it("shows error message when email is not valid", async () =&amp;gt; {
    fireEvent.changeText(usernameInput, "Mohamed");
    fireEvent.changeText(emailInput, "mohamed");

    await waitFor(() =&amp;gt; {
      fireEvent.press(submitButton);
    });

    await waitFor(() =&amp;gt; {
      expect(queryByText("email must be a valid email")).toBeTruthy();
    });
  });

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

&lt;/div&gt;



&lt;p&gt;Run the test script and make sure 4 tests have passed successfully!&lt;/p&gt;

&lt;h2&gt;
  
  
  Animated API:
&lt;/h2&gt;

&lt;p&gt;Unlike ReactJS and web development, where we use CSS to create animations, React Native require us to use the Animated API to build and maintain animations.&lt;/p&gt;

&lt;p&gt;Let's import &lt;strong&gt;Animated&lt;/strong&gt; so that we can get started&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
import {
  ...
  Animated,
} from "react-native";
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We want to create a smooth transition on rendering the component for the first time, from the bottom of the screen up to the form original position in the center.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
export default function App() {
  const translateY = useRef(new Animated.Value(100)).current;
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So here we create an instance of &lt;strong&gt;Animated.Value&lt;/strong&gt; and wrap it in a &lt;strong&gt;useRef&lt;/strong&gt; so that it gets created once, and then set the initial value to 100.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;}) =&amp;gt; {
...
          return (
            &amp;lt;Animated.View
              style={{
                transform: [{ translateY }],
              }}
            &amp;gt;
...
            &amp;lt;/Animated.View&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we replace the component that we want to apply the animation on which in this case is &lt;strong&gt;View&lt;/strong&gt; with &lt;strong&gt;Animated.View&lt;/strong&gt;, and we assign the &lt;strong&gt;translateY&lt;/strong&gt; to the animated value instance we just created.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://reactnative.dev/docs/animated" rel="noopener noreferrer"&gt;Animated&lt;/a&gt; exports six animatable component types: View, Text, Image, ScrollView, FlatList and SectionList, but you can also create your own using Animated.createAnimatedComponent().&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
useEffect(() =&amp;gt; {
    Animated.timing(translateY, {
      toValue: 0,
      duration: 500,
      useNativeDriver: true,
    }).start();
  }, []);
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Animated comes with helper functions that provide various animation types, for the on mount animation we will be using &lt;strong&gt;Animated.timing()&lt;/strong&gt; which by default uses &lt;strong&gt;easeInOut&lt;/strong&gt; curve but you can for sure pick your own &lt;a href="https://reactnative.dev/docs/easing" rel="noopener noreferrer"&gt;easing function&lt;/a&gt;. After that we set the duration and target value. &lt;/p&gt;

&lt;p&gt;To improve the animation performance, we are activating &lt;strong&gt;useNativeDriver&lt;/strong&gt; which will allow native code to perform the animation directly on the UI thread.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;By using the native driver, we send everything about the animation to native before starting the animation, allowing native code to perform the animation on the UI thread without having to go through the bridge on every frame. Once the animation has started, the JS thread can be blocked without affecting the animation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And finally starting the animations by calling &lt;strong&gt;start()&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now let's add a pressing effect to the submit button&lt;/p&gt;

&lt;p&gt;Let's create a new Animated.Value instance and set the initial value to 0&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
  const btnAnimation = useRef(new Animated.Value(0)).current;
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the pressing effect we need to create scaling animation&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const scale = btnAnimation.interpolate({
    inputRange: [0, 1],
    outputRange: [1, 0.8],
  });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we are &lt;strong&gt;interpolating&lt;/strong&gt; and mapping animation with the scaling values, in other words, we are simply telling animated to set the scale value to 0.8 when the animated value is 1 and set it back to 1 when the animated value is 0.&lt;/p&gt;

&lt;p&gt;You can find more information about interpolation in the official docs &lt;a href="https://reactnative.dev/docs/animations#interpolation" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
  const onPressIn = () =&amp;gt; {
    Animated.spring(btnAnimation, {
      toValue: 1,
      useNativeDriver: true,
    }).start();
  };
  const onPressOut = () =&amp;gt; {
    Animated.spring(btnAnimation, {
      toValue: 0,
      useNativeDriver: true,
    }).start();
  };
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we are using the spring animation which provides a &lt;a href="https://miro.medium.com/max/500/1*ROgAmFquVVrDH_O9k16cPA.gif" rel="noopener noreferrer"&gt;spring physics model&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
  const AnimatedPressable = Animated.createAnimatedComponent(Pressable);

...
&amp;lt;AnimatedPressable
                  style={[styles.pressable, { transform: [{ scale }] }]}
                  onPress={handleSubmit}
                  onPressIn={onPressIn}
                  testID="button"
                  onPressOut={onPressOut}
                &amp;gt;
                  &amp;lt;Text style={styles.ButtonText}&amp;gt;submit&amp;lt;/Text&amp;gt;
                &amp;lt;/AnimatedPressable&amp;gt;
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since Animated is not exporting Pressable we need to use createAnimatedComponent to make the component animatable, then we replace Pressable with the newly created one, and add transform with the scale value assigned to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Snapshot testing:
&lt;/h2&gt;

&lt;p&gt;Now that we have a stable working version of our app, we can perform snapshot testing. Snapshot testing ensures that there won't be any unexpected changes in UI. It typically takes a snapshot of the UI, compares the output with a stored copy, and if it detects any change occurred to the UI, the test simply fails.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  it("renders correctly", () =&amp;gt; {
    const tree = render(&amp;lt;App /&amp;gt;).toJSON();
    expect(tree).toMatchSnapshot();
  });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the test&lt;/p&gt;

&lt;p&gt;A new folder &lt;code&gt;__snapshots__&lt;/code&gt; should be created in &lt;code&gt;__tests__&lt;/code&gt;, that's where your snapshot is stored. &lt;/p&gt;

&lt;p&gt;Now try modifying any part of the form UI, and re-run the test&lt;/p&gt;

&lt;p&gt;You will find the snapshot test fails!&lt;/p&gt;

&lt;p&gt;Full code can be found in the github repo &lt;a href="https://github.com/thisisgazzar/react-native-formik-unit-testing" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion:
&lt;/h2&gt;

&lt;p&gt;Now that you know the basics of creating an animated form in React Native, and learned how you can cut off a lot of unnecessary code with Formik, you can get the most out of this tutorial by adding more validations to the form and performing unit testing upon them, and then play around with interpolations in Animated.&lt;/p&gt;

&lt;p&gt;Have a good one!&lt;/p&gt;

</description>
      <category>welcome</category>
      <category>webdev</category>
      <category>react</category>
      <category>django</category>
    </item>
    <item>
      <title>Build a Face Detection App using React, NodeJS and Clarifai</title>
      <dc:creator>Mohamed Elgazzar</dc:creator>
      <pubDate>Sat, 17 Dec 2022 21:09:35 +0000</pubDate>
      <link>https://dev.to/thisisgazzar/build-a-face-detection-app-using-react-nodejs-and-clarifai-3b24</link>
      <guid>https://dev.to/thisisgazzar/build-a-face-detection-app-using-react-nodejs-and-clarifai-3b24</guid>
      <description>&lt;p&gt;&lt;strong&gt;Computer Vision&lt;/strong&gt; has developed rapidly in the past few years. You might have come across the AI generated avatars that are booming lately all over social media, but Computer Vision applications are more varied, from face and ID verification to self-driving cars, ecommerce and retail industries, healthcare and more.&lt;/p&gt;

&lt;p&gt;Computer Vision is a subfield of AI that gives machines the sense of sight. Unlike human vision, a computer sees an image as just a bunch of integer values which represent intensities across the color spectrum. It uses a model which is provided by an algorithm and trained over a set of data to "learn" and recognize certain types of patterns.&lt;/p&gt;

&lt;p&gt;Let's take the AI generated avatars as an example, the model used for that would be trained over an algorithm that uses biometrics to analyze facial features to be able to recognize and extract a face from an image, modify it and apply it to the creation of the avatar.&lt;/p&gt;

&lt;p&gt;Without getting much into machine learning concepts as we will be building our app today using Clarifai which is a computer vision solution, &lt;strong&gt;&lt;em&gt;let's jump right off and start coding!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ysmaevqla43udjt6wxv.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ysmaevqla43udjt6wxv.gif" alt=" " width="498" height="279"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will start by building our &lt;strong&gt;server&lt;/strong&gt; that will be holding the &lt;strong&gt;Clarifai&lt;/strong&gt; integration logic&lt;/p&gt;

&lt;p&gt;Open your terminal and copy the following command into it&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mkdir face-detection-react-node-clarifai &amp;amp;&amp;amp; cd face-detection-react-node-clarifai &amp;amp;&amp;amp; mkdir server &amp;amp;&amp;amp; cd server&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now that we are on the server directory we initialize our project&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm init -y&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then we install some dependencies &lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install express dotenv clarifai-nodejs-grpc --save&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Let's now create &lt;strong&gt;index.js&lt;/strong&gt; file&lt;/p&gt;

&lt;p&gt;&lt;code&gt;touch index.js&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now we create a simple HTTP server &lt;/p&gt;

&lt;p&gt;Copy the following code into the file we just created&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require('express');
const http = require('http');
const app = express();

app.use(express.urlencoded({ extended: false }))
app.use(express.json())


const port = process.env.PORT || '8080';
app.set('port', port);
const server = http.createServer(app);
server.listen(port);
server.on('listening', () =&amp;gt; {
    console.log(`Listening on ${port}`);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we create &lt;strong&gt;detect.js&lt;/strong&gt; file which will contain the Clarifai logic&lt;/p&gt;

&lt;p&gt;&lt;code&gt;touch detect.js&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Before we get into the logic, let's hop over &lt;a href="https://clarifai.com/signup" rel="noopener noreferrer"&gt;Clarifai&lt;/a&gt; website and create a new account&lt;/p&gt;

&lt;p&gt;Once you log into your account, navigate to &lt;strong&gt;My Apps&lt;/strong&gt; where you will find your first application created (create one if not found), click on it, then go to &lt;strong&gt;App Settings&lt;/strong&gt;, and copy the &lt;strong&gt;API key&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now back to our &lt;strong&gt;server&lt;/strong&gt; directory, create a new &lt;strong&gt;.env&lt;/strong&gt; file and copy the following variable into it after you add the API key copied to clipboard.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CLARIFAI_AUTH_KEY=
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we start the integration &lt;/p&gt;

&lt;p&gt;We construct the Clarifai stub, which contains all the methods available in the Clarifai API, and the Metadata object that's used to authenticate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { ClarifaiStub, grpc } = require("clarifai-nodejs-grpc");
const dotenv = require('dotenv');
dotenv.config();

const metadata = new grpc.Metadata();
metadata.set("authorization", `Key ${process.env.CLARIFAI_AUTH_KEY}`);

const stub = ClarifaiStub.grpc();

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

&lt;/div&gt;



&lt;p&gt;We create a new promise to handle the &lt;strong&gt;PostModelOutputs&lt;/strong&gt; asynchronous method, then provide the &lt;strong&gt;model Id&lt;/strong&gt; that we get the predictions from. We are here using a public pre-optimized general Clarifai model. &lt;br&gt;
&lt;em&gt;&lt;strong&gt;You can dive more into public Clarifai models &lt;a href="https://clarifai.com/explore" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/strong&gt;&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const detectFace = (inputs) =&amp;gt; {
    return new Promise((resolve, reject) =&amp;gt; {
        stub.PostModelOutputs(
            {
                model_id: "a403429f2ddf4b49b307e318f00e528b",
                inputs: inputs
            },
            metadata,
            (error, response) =&amp;gt; {
                if (error) {
                    reject("Error: " + error);
                    return;
                }

                if (response.status.code !== 10000) {
                    reject("Received failed status: " + response.status.description + "\n" + response.status.details);
                    return;
                }

                let results = response.outputs[0].data.regions;
                resolve(results);
            }
        );
    })
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need to also supply the image that the model would process, so here we are assigning &lt;strong&gt;inputs&lt;/strong&gt; which is an array that we will construct in a moment.&lt;/p&gt;

&lt;p&gt;We should expect to receive the &lt;strong&gt;regions&lt;/strong&gt; of the faces that the model predicts as a result.&lt;/p&gt;

&lt;p&gt;Now we create a function to handle the asynchronous call that we are going to fire using the &lt;strong&gt;detectFace&lt;/strong&gt; function we just created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const handleDetect = async (req, res) =&amp;gt; {
    try{
        const { imageUrl } = req.body;
        const inputs = [
            {
                data: {
                    image: {
                        url: imageUrl
                    }
                }
            }
        ];
        const results = await detectFace(inputs);
        return res.send({
            results
        })
    }
    catch (error) {
        return res.status(400).send({
            error: error
        })
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We construct the &lt;strong&gt;inputs&lt;/strong&gt; array where we are going to assign the &lt;strong&gt;imageUrl&lt;/strong&gt; that we get from the frontend input.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;You can also provide the image directly by sending bytes but for this tutorial we are just going to use URLs.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Then we export the &lt;strong&gt;handleDetect&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = {
    handleDetect
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's now modify the &lt;strong&gt;server&lt;/strong&gt; file &lt;strong&gt;index.js&lt;/strong&gt; and add the &lt;strong&gt;detect route&lt;/strong&gt; that would be called later on the frontend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Full Code:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require('express');
const http = require('http');
const detect = require('./detect');
const app = express();

app.use(express.urlencoded({ extended: false }))
app.use(express.json())

app.post('/detect', (req, res) =&amp;gt; detect.handleDetect(req, res));

const port = process.env.PORT || '8080';
app.set('port', port);
const server = http.createServer(app);
server.listen(port);
server.on('listening', () =&amp;gt; {
    console.log(`Listening on ${port}`);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we add the &lt;strong&gt;start script&lt;/strong&gt; into &lt;strong&gt;package.json&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"scripts": {
    "start": "node ./index.js"
 },
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start the &lt;strong&gt;server&lt;/strong&gt; and make sure everything is working as expected.&lt;/p&gt;

&lt;p&gt;Now let’s navigate to the root directory and start building our &lt;strong&gt;frontend&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We will use &lt;strong&gt;create-react-app&lt;/strong&gt; to bootstrap our project.&lt;/p&gt;

&lt;p&gt;Copy the command below into your terminal&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npx create-react-app client &amp;amp;&amp;amp; cd client&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We install a couple of dependencies&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install styled-component axios –-save&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We start by specifying the proxy in &lt;strong&gt;package.json&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  "proxy": "http://localhost:8080"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are going to use &lt;strong&gt;styled-components&lt;/strong&gt; to build our app interface.&lt;/p&gt;

&lt;p&gt;In the src folder create components directory and inside of it create &lt;strong&gt;styled.js&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mkdir components &amp;amp;&amp;amp; cd components &amp;amp;&amp;amp; touch styled.js&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Copy the following code into the file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import styled from "styled-components";
import FaceDetectIcon from '../assets/FaceDetectIcon.svg';

const FaceDetectionWrapper = styled.div`
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
`
const Title = styled.h2`
    margin: 20px 0;
    font-weight: 800;
    font-size: 20px;
    text-align: center;
    color: #383838;
`
const ImagePreviewWrapper = styled.div`
    position: relative;
    width: ${props =&amp;gt; props.width};
    height: ${props =&amp;gt; props.height};
    display: flex;
    align-items: center;
    justify-content: center;
    background: #F9F9FB;
    background-image: url(${FaceDetectIcon});
    background-repeat: no-repeat;
    background-position: center;
    border-radius: 16px;
    border: 2px dashed #D2D7E5;
`
const Image = styled.img`
    border-radius: ${props =&amp;gt; props.borderRadius};
`


const FormWrapper = styled.form`
    display: flex;
    flex-direction: column;
`
const InputWrapper = styled.input`
    width: 500px;
    height: 45px;
    margin: 12px 0;
    padding: 8px 20px;
    box-sizing: border-box;
    background: #FFFFFF;
    border: 1px solid #D2D7E5;
    border-radius: 16px;
    outline: none;
`
const SubmitButton = styled.button`
    width: 500px;
    height: 45px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    border-radius: 16px;
    border: none;
    outline: none;
    background: #576684;
    color: #FFFFFF;
    font-weight: 300;
    font-size: 20px;
    text-align: center;
    color: #FFFFFF;
`

const FaceBox = styled.div`
  position: absolute;
  border: 2px solid #FFFFFF;
  border-radius: 8px;
`;
const FaceBoxesWrapper = styled.div`

`;




export {
    FaceDetectionWrapper,
    Title,
    ImagePreviewWrapper,
    Image,
    FormWrapper,
    InputWrapper,
    SubmitButton,
    FaceBox,
    FaceBoxesWrapper
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create &lt;strong&gt;Form.js&lt;/strong&gt; file where we are going to set our input&lt;/p&gt;

&lt;p&gt;&lt;code&gt;touch Form.js&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Copy the code below into it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {
  FormWrapper,
  InputWrapper,
  SubmitButton
} from './styled';


const FaceDetectionForm = ({ setInput, input, detectFaces, loading }) =&amp;gt; {
    return(
        &amp;lt;FormWrapper onSubmit={detectFaces}&amp;gt;
            &amp;lt;InputWrapper type="text" placeholder="Enter Image Link" onChange={e =&amp;gt; setInput(e.target.value)} value={input}/&amp;gt;
            &amp;lt;SubmitButton type="submit"&amp;gt;{loading ? "Loading..." : "Detect"}&amp;lt;/SubmitButton&amp;gt;
        &amp;lt;/FormWrapper&amp;gt;
    )
}

export default FaceDetectionForm;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing but a simple input and a submit button.&lt;/p&gt;

&lt;p&gt;Create &lt;strong&gt;Preview.js&lt;/strong&gt; file where we are going to view the image with the received face predictions&lt;/p&gt;

&lt;p&gt;&lt;code&gt;touch Preview.js&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Copy the following code into it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {
    ImagePreviewWrapper,
    Image,
    FaceBoxesWrapper,
    FaceBox
} from './styled';

const FaceDetectionPreview = ({ boxDimensions, imageUrl }) =&amp;gt; {

    const faceBoxGenerator = (dimensions) =&amp;gt; {
        let boxes = [];

        for(let i = 0; i &amp;lt; dimensions.length; i++){
            boxes.push(&amp;lt;FaceBox key={i}
            style={{
                top: dimensions[i].topRow, 
                right: dimensions[i].rightCol, 
                bottom: dimensions[i].bottomRow, 
                left: dimensions[i].leftCol
            }}&amp;gt;&amp;lt;/FaceBox&amp;gt;)
        }
        return &amp;lt;FaceBoxesWrapper&amp;gt;{boxes}&amp;lt;/FaceBoxesWrapper&amp;gt;
    }

    return (
        &amp;lt;ImagePreviewWrapper width="500px" height={imageUrl ? "auto" : "300px"}&amp;gt;
            {imageUrl &amp;amp;&amp;amp; &amp;lt;Image src={imageUrl}
                id="inputImage"
                alt="face detect output" 
                width='500px' height='auto'
                borderRadius="16px"
            /&amp;gt;}
            {faceBoxGenerator(boxDimensions)}
        &amp;lt;/ImagePreviewWrapper&amp;gt;          
    );
}

export default FaceDetectionPreview;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, let's do our API call&lt;/p&gt;

&lt;p&gt;We will use Axios as our HTTP client&lt;/p&gt;

&lt;p&gt;Copy the code below into &lt;strong&gt;App.js&lt;/strong&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 { useState } from "react";
import axios from "axios";
import {
  FaceDetectionWrapper,
  Title
} from './styled';
import FaceDetectionForm from './Form';
import FaceDetectionPreview from './Preview';
import '../App.css';

function App() {

  const [input, setInput] = useState("");
  const [imageUrl, setImageUrl] = useState("");
  const [boxDimentions, setBoxDimentions] = useState([]);
  const [loading, setLoading] = useState(false);


  const detectFaces = async (e) =&amp;gt; {
    e.preventDefault();
    setBoxDimentions([]);
    setLoading(true);
    setImageUrl(input);
    const boxDimensionArray = []
    try {
      const detect = await axios.post('/detect', {
        imageUrl: input
      });
      const results = detect.data.results;
      results.forEach(region =&amp;gt; {
        const faceBoxDimentions = region.region_info.bounding_box;
        const image = document.getElementById('inputImage');
        const width = Number(image.width);
        const height = Number(image.height);
        const boxDimension =  {
          leftCol: faceBoxDimentions.left_col * width,
          topRow: faceBoxDimentions.top_row * height,
          rightCol: width - (faceBoxDimentions.right_col * width),
          bottomRow: height - (faceBoxDimentions.bottom_row * height)
        }
        boxDimensionArray.push(boxDimension);
      });
      setBoxDimentions(boxDimensionArray);
    } catch (error) {
      console.error(error);
    } finally {
      setLoading(false);
    }
  }

  return (
    &amp;lt;FaceDetectionWrapper&amp;gt;
      &amp;lt;Title&amp;gt;Face Detection&amp;lt;/Title&amp;gt;
      &amp;lt;FaceDetectionPreview boxDimensions={boxDimentions} imageUrl={imageUrl} /&amp;gt;
      &amp;lt;FaceDetectionForm setInput={setInput} input={input} detectFaces={detectFaces} loading={loading} /&amp;gt;
    &amp;lt;/FaceDetectionWrapper&amp;gt;
  );
}

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As mentioned earlier, we should be expecting an array of predictions for the image that we provided, then we target the image width and height to be able to calculate each box’s side position.&lt;/p&gt;

&lt;p&gt;As mentioned earlier, we should be expecting an array of predictions for the image that we provided, then we target the image’s width and height to be able to calculate each box's side positioning on the preview.&lt;/p&gt;

&lt;p&gt;Let's now run the app et voila!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmr0sjur19qtvj29u2p7v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmr0sjur19qtvj29u2p7v.png" alt=" " width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Full code can be found in the github repo &lt;a href="https://github.com/thisisgazzar/face-detection-node-react-clarifai" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion:
&lt;/h2&gt;

&lt;p&gt;There are a lot of &lt;strong&gt;computer vision&lt;/strong&gt; and &lt;strong&gt;face detection&lt;/strong&gt; applications and use cases out there, and soon this technology will go beyond and become a part of our everyday life (If it has not become already!). &lt;br&gt;
I'm planning to get more into AI and Machine learning, and I will do articles and tutorials about &lt;strong&gt;TensorFlow&lt;/strong&gt; and &lt;strong&gt;OpenCV&lt;/strong&gt;, so follow me and keep posted!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S.&lt;/strong&gt; I'm currently in the middle of building my own lab on my website. &lt;br&gt;
Subscribe &lt;a href="https://thisisgazzar.com/lab" rel="noopener noreferrer"&gt;here&lt;/a&gt; and get notified when the project is launched.&lt;/p&gt;

&lt;p&gt;Have a good one!&lt;/p&gt;

</description>
      <category>react</category>
      <category>node</category>
      <category>tutorial</category>
      <category>ai</category>
    </item>
    <item>
      <title>Build your first Web3 Chrome Extension using Typescript</title>
      <dc:creator>Mohamed Elgazzar</dc:creator>
      <pubDate>Wed, 16 Nov 2022 23:27:31 +0000</pubDate>
      <link>https://dev.to/thisisgazzar/build-your-first-web3-chrome-extension-using-typescript-18e2</link>
      <guid>https://dev.to/thisisgazzar/build-your-first-web3-chrome-extension-using-typescript-18e2</guid>
      <description>&lt;p&gt;Today, I'm going to walk you through the steps of building a simple &lt;strong&gt;web3 chrome extension&lt;/strong&gt; that gets the ETH balance of a given wallet address.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;In this tutorial, you will learn the following:&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setting up a Webpack dev environment.&lt;/li&gt;
&lt;li&gt;Some of Typescript core concepts.&lt;/li&gt;
&lt;li&gt;Making a Web3 call.&lt;/li&gt;
&lt;li&gt;Creating a Chrome Extension and learning about Manifest.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I assume you have basic Javascript knowledge, so I won't get much into the code structure.&lt;/p&gt;

&lt;p&gt;Before we start, make sure you have &lt;strong&gt;Nodejs&lt;/strong&gt; and &lt;strong&gt;NPM&lt;/strong&gt; installed on your machine.&lt;/p&gt;

&lt;p&gt;Let's jump right off and start setting up our environment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjc44ddtyu9ej0kmmasez.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjc44ddtyu9ej0kmmasez.gif" alt=" " width="498" height="211"&gt;&lt;/a&gt;&lt;br&gt;
We start with initializing our project and creating the &lt;code&gt;package.json&lt;/code&gt; file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir ts-web3-extension &amp;amp;&amp;amp; cd ts-web3-extension &amp;amp;&amp;amp; npm init -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Typescript:
&lt;/h2&gt;

&lt;p&gt;Typescript is a strongly typed language developed and maintained by &lt;strong&gt;Microsoft&lt;/strong&gt;. It’s a superset of &lt;strong&gt;Javascript&lt;/strong&gt; built up on it.&lt;br&gt;
Unlike Javascript which is dynamically typed, Typescript provides optional &lt;strong&gt;static typing&lt;/strong&gt; and extra features that help you identify common errors and write much cleaner code.&lt;/p&gt;

&lt;p&gt;You can install Typescript into your project or globally on your machine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i typescript --save-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Webpack:
&lt;/h2&gt;

&lt;p&gt;Webpack is &lt;strong&gt;a module bundler&lt;/strong&gt; for Javascript applications, it helps bundle and optimize different files we have in the app, making the code &lt;strong&gt;shorter and usable&lt;/strong&gt; on the browser.&lt;/p&gt;

&lt;p&gt;To start building our development setup using Webpack, we need to install some dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i webpack webpack-cli html-webpack-plugin clean-webpack-plugin --save-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, webpack can only compile and bundle &lt;strong&gt;Javascript files&lt;/strong&gt;, so we will need to use &lt;strong&gt;a loader&lt;/strong&gt; which will allow us to handle Typescript files.&lt;/p&gt;

&lt;p&gt;Copy the command below into your terminal to install ts-loader&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i ts-loader --save-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we have installed all the dependencies needed, let's start building our environment.&lt;/p&gt;

&lt;p&gt;We create tsconfig.ts file in the root directory&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch tsconfig.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;tsconfig.json&lt;/code&gt; indicates that this is the root of a &lt;strong&gt;TypeScript project&lt;/strong&gt;. &lt;br&gt;
Let's leave the file empty for now or just add &lt;code&gt;{}&lt;/code&gt; which will let us use the compiler's defaults.&lt;/p&gt;

&lt;p&gt;Next, we create &lt;code&gt;webpack.config.js&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;touch webpack.config.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, copy the code below into it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const HTMLWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const path = require('path');

module.exports = {
  mode: 'development',
  entry: './src/index.ts',
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: 'index.js'
  },
  devtool: 'cheap-module-source-map',
  module: {
    rules: [
      {
        test: /\.ts$/,
        exclude: /node_modules/,
        use: {
          loader: 'ts-loader',
        },
      }
    ],
  },
  plugins: [
    new HTMLWebpackPlugin(),
    new CleanWebpackPlugin(),
  ]
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, let’s explain each config option individually&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mode&lt;/code&gt; basically allows you to set what kind of build you want, so here we are setting it to &lt;code&gt;development&lt;/code&gt; in which case the build is formatted by adding line breaks and detailed comments making it look more readable. If you change that to &lt;code&gt;production&lt;/code&gt; you will notice how the build gets minified and compressed.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;entry&lt;/code&gt; obviously tells webpack its entry point, where it should start its magic on.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;output&lt;/code&gt; helps us specify the name of the build file and where it should be located, so here we use Node’s path module to provide us a utility to work with directory paths instead of having to write it ourselves, then we call the file &lt;code&gt;index.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;___dirname is an env variable that returns the directory path of the current JS file, which is the root. _&lt;/p&gt;

&lt;p&gt;After that, we set &lt;code&gt;devtool&lt;/code&gt; to &lt;code&gt;​​cheap-module-source-map&lt;/code&gt;.&lt;br&gt;
By default, devtool uses &lt;code&gt;eval&lt;/code&gt; function in its source map styling which is a bad practice and chrome doesn't allow using it, so this would remove it.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;module&lt;/code&gt; we specify a set of rules and here we determine how webpack will handle Typescript files using the &lt;code&gt;ts-loader&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We set a regular expression in &lt;code&gt;test&lt;/code&gt; of what file endings to run the ts-loader on, and in &lt;code&gt;exclude&lt;/code&gt; we are telling webpack not to traverse through the &lt;code&gt;node_modules&lt;/code&gt; dependencies.&lt;/p&gt;

&lt;p&gt;Unlike loaders which apply changes on files before they are bundled, &lt;code&gt;plugins&lt;/code&gt; work on the whole generated bundle and control how they are created and in which form.&lt;/p&gt;

&lt;p&gt;Here we are adding a couple of plugins, &lt;code&gt;html-webpack-plugin&lt;/code&gt; generates an HTML file that includes our webpack bundle using a script tag without the need to create it manually. &lt;code&gt;clean-webpack-plugin&lt;/code&gt; simply removes all files inside the build directory after every successful rebuild.&lt;/p&gt;

&lt;p&gt;Okay, let's move onto the main part and start building our app&lt;/p&gt;

&lt;p&gt;We create &lt;code&gt;src&lt;/code&gt; directory that we specified in the webpack entry and inside of it we create &lt;code&gt;index.ts&lt;/code&gt; which will contain all of our code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir src &amp;amp;&amp;amp; cd src &amp;amp;&amp;amp; touch index.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the following code into index.ts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let appEl = document.createElement('div');
appEl.setAttribute('id', 'app')
document.body.appendChild(appEl);

let app = document.getElementById('app')!;

let balanceEl = document.createElement('h2');
balanceEl.setAttribute("id", "balance");
balanceEl.innerText = "0 ETH";
app.appendChild(balanceEl);

let inputEl = document.createElement('input');
inputEl.setAttribute('type', 'text');
inputEl.setAttribute('id', 'address-input');
inputEl.setAttribute('name', 'address-input');
inputEl.setAttribute('placeholder', "Wallet Address');
app.appendChild(inputEl);


let submitEl = document.createElement('button');
submitEl.setAttribute('id', 'submit-btn');
submitEl.innerText = 'Get Balance';
app.appendChild(submitEl);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we create our interface for the app, just a simple input, a button and a text element.&lt;/p&gt;

&lt;p&gt;Notice how document.getElementById('app') is followed by an exclamation mark &lt;code&gt;(!)&lt;/code&gt;. Typescript forces us to be clearer while writing our code. It's not sure that it would return something that is not null or undefined so it throws an error, and by adding the non-null assertion operator, we are stating that the element must return something that actually makes sense.&lt;/p&gt;

&lt;p&gt;Now we build the functionality&lt;/p&gt;

&lt;h2&gt;
  
  
  Web3.js
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;web3.js&lt;/code&gt; is a collection of libraries written in Nodejs, used to help us interact with Ethereum nodes.&lt;/p&gt;

&lt;p&gt;Let's start by installing the web3 dependency&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i web3 --save
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We import web3 into index.ts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Web3 = require('web3');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we add the following function&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const getBalance = async () =&amp;gt; {
  submitEl.innerText = "Loading...";
  submitEl.style.pointerEvents = 'none';
  const infura = 'https://goerli.infura.io/v3/your-api-key';
  const web3 = new Web3(new Web3.providers.HttpProvider(infura));
  let addressValue = (document.getElementById('address-input') as HTMLFormElement).value;
  let balance = await web3.eth.getBalance(addressValue);
  balance = web3.utils.fromWei(balance, 'ether');
  balanceEl.innerText = balance + " ETH";
  submitEl.innerText = "Get Balance";
  submitEl.style.pointerEvents = "auto";
};

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

&lt;/div&gt;



&lt;p&gt;By default Typescript sets the type of an async function's return to &lt;code&gt;Promise&amp;lt;type&amp;gt;&lt;/code&gt; because it's guaranteed that it will return a promise and since we don't typically have a return value in our function it sets the type to &lt;code&gt;void&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As we mentioned earlier, Typescript forces us to be explicit, so here in addressValue we are setting &lt;code&gt;document.getElementById('address-input')&lt;/code&gt; as &lt;strong&gt;HTMLFormElement&lt;/strong&gt; just to assure that this input element has an actual value.&lt;/p&gt;

&lt;p&gt;To connect to the Ethereum node, we pass a &lt;strong&gt;provider&lt;/strong&gt; into the web3 constructor, here we are passing an &lt;code&gt;HttpProvider&lt;/code&gt;, but you can also use &lt;strong&gt;WebSocketProvider&lt;/strong&gt; which allows subscriptions and &lt;strong&gt;IpcProvider&lt;/strong&gt; if the node is running locally. &lt;/p&gt;

&lt;p&gt;We then get our network endpoint from &lt;a href="https://app.infura.io/dashboard" rel="noopener noreferrer"&gt;Infura&lt;/a&gt; after you create an API key and pass it right into the &lt;strong&gt;provider&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here we used &lt;code&gt;fromWei&lt;/code&gt; utility to convert the balance that we get into a readable ether value.&lt;/p&gt;

&lt;p&gt;Full code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Web3 = require('web3');

let appEl = document.createElement('div');
appEl.setAttribute('id', 'app')
document.body.appendChild(appEl);

let app = document.getElementById('app')!;

let balanceEl = document.createElement('h2');
balanceEl.setAttribute("id", "balance");
balanceEl.innerText = "0 ETH";
app.appendChild(balanceEl);

let inputEl = document.createElement('input');
inputEl.setAttribute("type", "text");
inputEl.setAttribute("id", "address-input");
inputEl.setAttribute("name", "address-input");
inputEl.setAttribute("placeholder", "Wallet Address");
app.appendChild(inputEl);


let submitEl = document.createElement('button');
submitEl.setAttribute("id", "submit-btn");
submitEl.innerText = "Get Balance";
app.appendChild(submitEl);

const getBalance = async () =&amp;gt; {
  submitEl.innerText = "Loading...";
  submitEl.style.pointerEvents = 'none';
  const infura = 'https://goerli.infura.io/v3/your-api-key';
  const web3 = new Web3(new Web3.providers.HttpProvider(infura));
  let addressValue = (document.getElementById('address-input') as HTMLFormElement).value;
  let balance = await web3.eth.getBalance(addressValue);
  balance = web3.utils.fromWei(balance, 'ether');
  balanceEl.innerText = balance + " ETH";
  submitEl.innerText = "Get Balance";
  submitEl.style.pointerEvents = "auto";
};

(document.getElementById("submit-btn") as HTMLFormElement).onclick = (e) =&amp;gt; {
  e.preventDefault();
  getBalance();
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we move to the interesting part of how to turn all of that into a Chrome extension.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chrome Extension and Manifest:
&lt;/h2&gt;

&lt;p&gt;Manifest is the system that governs how Chrome extensions interact with your browser.&lt;/p&gt;

&lt;p&gt;Let's create &lt;code&gt;public&lt;/code&gt; in the root directory and inside of it we create &lt;code&gt;manifest.json&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;mkdir public &amp;amp;&amp;amp; cd public &amp;amp;&amp;amp; touch manifest.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;manifest.json&lt;/code&gt; we specify &lt;strong&gt;basic metadata and information&lt;/strong&gt; about our extension such as the name, the description, the version that chrome currently supports, and aspects of the extension's functionality such as actions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "name": "Web3Balance",
    "description": "Get ETH Balance of any given address",
    "version": "1.0",
    "manifest_version": 3,
    "action": {
      "default_popup": "index.html"
    }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We set the default popup which appears when the user clicks the extension's icon into the html file that webpack is going to generate for us.&lt;/p&gt;

&lt;p&gt;Let's now install an additional plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i copy-webpack-plugin --save-dev

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

&lt;/div&gt;



&lt;p&gt;copy-webpack-plugin as the name implies copies the &lt;code&gt;manifest.json&lt;/code&gt; file that we  have inside &lt;code&gt;public&lt;/code&gt; right into the &lt;code&gt;dist&lt;/code&gt; folder so that the manifest file is able to access the generated bundle.&lt;/p&gt;

&lt;p&gt;Let’s now modify &lt;code&gt;webpack.config.js&lt;/code&gt; and add the plugin into it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const HTMLWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const path = require('path');

module.exports = {
  mode: 'development',
  entry: "./src/index.ts",
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: 'index.js'
  },
  devtool: "​​cheap-module-source-map",
  module: {
    rules: [
      {
        test: /\.ts$/,
        exclude: /node_modules/,
        use: {
          loader: "ts-loader",
        },
      }
    ],
  },
  plugins: [
    new HTMLWebpackPlugin(),
    new CopyWebpackPlugin({
      patterns: [
        {from: "public", to: "."}
      ],
    }),
    new CleanWebpackPlugin(),
  ]
};

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

&lt;/div&gt;



&lt;p&gt;Now we want to add some styling to our app and for that we will need a couple of loaders&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i css-loader style-loader --save-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;css-loader&lt;/code&gt; simply collects all of our project's css files helping webpack to resolve them, and &lt;code&gt;style-loader&lt;/code&gt; takes the generated output and put it inside the &lt;code&gt;style&lt;/code&gt; tags.&lt;/p&gt;

&lt;p&gt;Let's modify &lt;code&gt;webpack.config.js&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;const HTMLWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const path = require('path');

module.exports = {
  mode: 'development',
  entry: "./src/index.ts",
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: 'index.js'
  },
  devtool: "​​cheap-module-source-map",
  module: {
    rules: [
      {
        test: /\.ts$/,
        exclude: /node_modules/,
        use: {
          loader: "ts-loader",
        },
      },
      {
        test: /\.css$/,
        exclude: /node_modules/,
        use: ["style-loader", "css-loader"],
      }
    ],
  },
  plugins: [
    new HTMLWebpackPlugin(),
    new CopyWebpackPlugin({
      patterns: [
        {from: "public", to: "."}
      ],
    }),
    new CleanWebpackPlugin(),
  ]
};

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

&lt;/div&gt;



&lt;p&gt;Create &lt;code&gt;style.css&lt;/code&gt; in the &lt;code&gt;src&lt;/code&gt; directory and copy the following code into it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#app{
    width: 350px;
    padding: 20px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
}

#balance{
    margin: 0;
}

#address-input{
    width: 100%;
    height: 30px;
    padding: 6px 15px;
    margin: 20px 0;
    border: none;
    outline: none;
    border-radius: 25px;
    background-color: #f3f3f3;
}

#submit-btn{
    width: 50%;
    padding: 8px;
    cursor: pointer;
    border: none;
    border-radius: 8px;
    outline: none;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we import the file into &lt;code&gt;index.ts&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 './style.css';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, let's add the build script into &lt;code&gt;package.json&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;"scripts": {
    "build": "webpack"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we run the following command in our terminal&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the build is done, you will find the &lt;code&gt;dist&lt;/code&gt; folder created in the root directory containing the generated bundle.&lt;/p&gt;

&lt;p&gt;Let's now head to the Chrome browser and navigate to &lt;code&gt;chrome://extensions&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;On the top left of the page click on &lt;strong&gt;Load unpacked&lt;/strong&gt; to fetch the &lt;code&gt;dist&lt;/code&gt; directory&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyb4ivmmvjcspcdp4q0jp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyb4ivmmvjcspcdp4q0jp.png" alt=" " width="800" height="242"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Et voila!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwl5d2c231p8st3ml2sb8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwl5d2c231p8st3ml2sb8.png" alt=" " width="800" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Full code can be found in the github repo &lt;a href="https://github.com/thisisgazzar/ts-web3-extension" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion:
&lt;/h2&gt;

&lt;p&gt;Congrats! You just created your first ever Web3 Chrome Extension!&lt;br&gt;
With Typescript you may put some more effort writing your code, however I believe the effort pays off and the benefits are worth it.&lt;br&gt;
I'm planning to build more complex projects that cover a lot of in-depth Web3 topics, so keep posted!&lt;/p&gt;

&lt;p&gt;Have a good one!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>typescript</category>
      <category>web3</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>RTK Query vs Redux Saga: What to choose for your next project?</title>
      <dc:creator>Mohamed Elgazzar</dc:creator>
      <pubDate>Thu, 03 Nov 2022 20:14:52 +0000</pubDate>
      <link>https://dev.to/thisisgazzar/rtk-query-vs-redux-saga-what-to-choose-for-your-next-project-4j5g</link>
      <guid>https://dev.to/thisisgazzar/rtk-query-vs-redux-saga-what-to-choose-for-your-next-project-4j5g</guid>
      <description>&lt;p&gt;Today we're going to discuss and compare &lt;strong&gt;Redux Saga&lt;/strong&gt; and &lt;strong&gt;RTK Query&lt;/strong&gt; approaches for API access and async tasks. We will go through both of them and in the end, you will have all the knowledge that will help you decide which one to use in your project!&lt;/p&gt;

&lt;p&gt;So your application is getting bigger, and you decide to use Redux as your state management for the project.&lt;/p&gt;

&lt;p&gt;Now, you want to connect your app with an external API! &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In Redux&lt;/strong&gt; you can't dispatch asynchronous actions directly in the store, so you will typically need to install an async middleware such as &lt;em&gt;Redux Thunk&lt;/em&gt; or &lt;em&gt;Redux Saga&lt;/em&gt;, that will help encapsulate asynchronous side effects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RTK&lt;/strong&gt; provides built-in tools that can be used for API interactions such as &lt;strong&gt;createReduxThunk&lt;/strong&gt; and &lt;strong&gt;RTK Query&lt;/strong&gt; which is indeed built on top of cAT and other RTK APIs internally. It is purpose built for data fetching so it simplifies the async logic that is usually handwritten.&lt;/p&gt;

&lt;p&gt;In this tutorial, I assume you have basic knowledge of React and Redux.&lt;/p&gt;

&lt;p&gt;I'm gonna show you how to integrate &lt;strong&gt;Saga&lt;/strong&gt; into &lt;strong&gt;plain Redux&lt;/strong&gt; and &lt;strong&gt;RTK&lt;/strong&gt;, explore some of its powerful features, and then dive into &lt;strong&gt;RTK Query&lt;/strong&gt; and how it cuts down a lot of data fetching and caching logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Redux Saga
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Redux-Saga&lt;/strong&gt; is a powerful middleware library that allows Redux store to asynchronously interact with external APIs.&lt;/p&gt;

&lt;p&gt;Redux-Saga uses an advanced ES6 feature called &lt;strong&gt;generator&lt;/strong&gt;, it's simply a kind of function that can be paused in between the execution, similar to what happens when using &lt;em&gt;async/await&lt;/em&gt;, which makes life easier while managing asynchronous calls.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Now let's do some coding and start building our app!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We will be setting up a simple API call that gets a list of random users - I will start with integrating Saga using &lt;strong&gt;plain Redux&lt;/strong&gt; then try it out with &lt;strong&gt;RTK&lt;/strong&gt; and see the difference between both integrations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Plain Redux:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt; - Initialize a React application&lt;/p&gt;

&lt;p&gt;We will be using CRA to bootstrap our React app.&lt;br&gt;
Run this command in the terminal:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npx create-react-app users-list &amp;amp;&amp;amp; cd users-list&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt; - Setting up Redux&lt;/p&gt;

&lt;p&gt;To set up Redux and integrate Saga we will need to install some packages:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install redux react-redux redux-saga --save&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Let's now create our store&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a new directory in the src folder and name it &lt;strong&gt;store&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Inside of it create &lt;strong&gt;configureStore.js&lt;/strong&gt; &lt;/li&gt;
&lt;li&gt;Copy the following code into the file we just created.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createStore, combineReducers } from 'redux';
import users from '../reducers/reducer';

export default function configureStore() {
    const reducers = combineReducers({ users });

    return {
        ...createStore(reducers)
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now we set up the actions and root reducer&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create an &lt;strong&gt;actions&lt;/strong&gt; directory in &lt;strong&gt;src&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Create &lt;strong&gt;action.js&lt;/strong&gt; file&lt;/li&gt;
&lt;li&gt;Copy following code into it
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const GET_USERS_FETCH = 'GET_USERS_FETCH';
export const GET_USERS_SUCCESS = 'GET_USERS_SUCCESS';

export const getUsersFetch = () =&amp;gt; ({
    type: GET_USERS_FETCH
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Create a &lt;strong&gt;reducers&lt;/strong&gt; directory in src&lt;/li&gt;
&lt;li&gt;Create &lt;strong&gt;reducer.js&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Copy the following code into it.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { GET_USERS_SUCCESS } from "../actions/action";

const users = (state = { users: [] }, action) =&amp;gt; {
    switch (action.type){
        case GET_USERS_SUCCESS:
            return { ...state, users: action.users }
        default: 
            return state;
    }
}

export default users;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now we update &lt;strong&gt;index.js&lt;/strong&gt; file in the root directory&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 from 'react';
import ReactDOM from 'react-dom/client';
import { Provider } from 'react-redux';
import App from './App';
import configureStore from './store/configureStore';

const store = configureStore();

const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(
  &amp;lt;React.StrictMode&amp;gt;
    &amp;lt;Provider store={store}&amp;gt;
      &amp;lt;App /&amp;gt;
    &amp;lt;/Provider&amp;gt;
  &amp;lt;/React.StrictMode&amp;gt;
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt; - Integrate our first Saga&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create &lt;strong&gt;sagas&lt;/strong&gt; folder in the root directory&lt;/li&gt;
&lt;li&gt;Create &lt;strong&gt;saga.js&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As we mentioned earlier sagas are implemented using &lt;strong&gt;generators&lt;/strong&gt;.&lt;br&gt;
Let's create the first &lt;strong&gt;generator&lt;/strong&gt; function.&lt;/p&gt;

&lt;p&gt;Copy the code below into the &lt;strong&gt;saga&lt;/strong&gt; file we just created&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { takeEvery } from "redux-saga/effects";
import { GET_USERS_FETCH } from "../actions/action";


function* getUsersSaga() {
    yield takeEvery(GET_USERS_FETCH, getUsersRequest);
}

export default getUsersSaga;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the &lt;em&gt;asterisk&lt;/em&gt; that follows the function keyword, this is how you define a &lt;strong&gt;generator&lt;/strong&gt; function in ES6. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;yield&lt;/strong&gt; pauses the function until what comes after it is fulfilled, you can think of it as &lt;em&gt;await&lt;/em&gt; in async function.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;takeLatest&lt;/strong&gt; is a special redux saga effect - &lt;em&gt;Effects are simply instructions to the middleware to perform some operations&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So here &lt;strong&gt;takeLatest&lt;/strong&gt; fires the instance immediately and takes the latest version of data, terminating any previous active request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;takeLatest&lt;/strong&gt; takes two parameters, the first is an action type string that triggers the function that we put in the second parameter.&lt;/p&gt;

&lt;p&gt;There are much more helpful Saga effects - &lt;em&gt;There is &lt;strong&gt;takeEvery&lt;/strong&gt; which allows multiple requests to be fired concurrently, so you can start a new instance without terminating the previous active request.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;throttle&lt;/strong&gt; is also very useful to prevent too many API requests.&lt;/p&gt;

&lt;p&gt;For more info about Saga effects check the &lt;a href="https://redux-saga.js.org/docs/recipes" rel="noopener noreferrer"&gt;official docs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy the code down below and update the &lt;strong&gt;saga&lt;/strong&gt; file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { call, put, takeEvery } from "redux-saga/effects";
import { GET_USERS_FETCH, GET_USERS_SUCCESS } from "../actions/action";

function* getUsersRequest() {
    const users = yield call(() =&amp;gt; fetch('https://jsonplaceholder.typicode.com/users'));
    const formattedUsers = yield users.json(); 
    yield put({ type: GET_USERS_SUCCESS, formattedUsers });
}

function* getUsersSaga() {
    yield takeEvery(GET_USERS_FETCH, getUsersRequest);
}

export default getUsersSaga;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we add the function that contains the actual logic for the API call.&lt;br&gt;
&lt;strong&gt;put&lt;/strong&gt; obviously puts the data we got from the API response and updates the store with it.&lt;/p&gt;

&lt;p&gt;Now let's wire things up and update the &lt;strong&gt;store&lt;/strong&gt; with the code below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createStore, combineReducers, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga';
import users from '../reducers/reducer';

export default function configureStore() {
    const sagaMiddleware = createSagaMiddleware();
    const reducers = combineReducers({ users });

    return {
        ...createStore(reducers, applyMiddleware(sagaMiddleware)),
        runSaga: sagaMiddleware.run,
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Above we simply create &lt;em&gt;a saga middleware&lt;/em&gt; instance and return the run function that we are gonna pass the saga we just created into. &lt;/p&gt;

&lt;p&gt;Now we update the &lt;strong&gt;index&lt;/strong&gt; file&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 from 'react';
import ReactDOM from 'react-dom/client';
import { Provider } from 'react-redux';
import App from './App';
import configureStore from './store/configureStore';
import getUsersSaga from './sagas/saga';

const store = configureStore();
store.runSaga(getUsersSaga);

const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(
  &amp;lt;React.StrictMode&amp;gt;
    &amp;lt;Provider store={store}&amp;gt;
      &amp;lt;App /&amp;gt;
    &amp;lt;/Provider&amp;gt;
  &amp;lt;/React.StrictMode&amp;gt;
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, let's update our JSX - copy the code below into &lt;strong&gt;App.js&lt;/strong&gt; and run the app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getUsersFetch } from './actions/action';


function App(){
  const dispatch = useDispatch();
  const users = useSelector(state =&amp;gt; state.users.users);
  useEffect(() =&amp;gt; {
    dispatch(getUsersFetch())
  }, [dispatch])
  return (
    &amp;lt;div className="App"&amp;gt;
      {users.map(user =&amp;gt; (&amp;lt;h2 key={Math.random()}&amp;gt;{user.name}&amp;lt;/h2&amp;gt;))}
    &amp;lt;/div&amp;gt;
  );
}
export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's build the same saga functionality with &lt;strong&gt;RTK&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We will first need to install the toolkit dependency&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install @reduxjs/toolkit --save&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt; - Create usersSlice&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RTK&lt;/strong&gt; introduces &lt;strong&gt;slice&lt;/strong&gt; which essentially replaces &lt;em&gt;reducers&lt;/em&gt; and &lt;em&gt;actions&lt;/em&gt; with &lt;strong&gt;a single feature&lt;/strong&gt; that auto generates &lt;strong&gt;action types&lt;/strong&gt; and &lt;strong&gt;action creators&lt;/strong&gt;,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Let's create a new folder in the root directory and name it &lt;strong&gt;features&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Inside of it create &lt;strong&gt;usersSlice.js&lt;/strong&gt; and copy the code below into it.&lt;/li&gt;
&lt;li&gt;We initialized a &lt;em&gt;slice&lt;/em&gt; using &lt;strong&gt;createSlice&lt;/strong&gt; which is a function that takes an object of slice &lt;em&gt;name&lt;/em&gt;, &lt;em&gt;initialState&lt;/em&gt; and &lt;em&gt;reducer&lt;/em&gt; functions, then export the &lt;em&gt;actions&lt;/em&gt; that redux generated for us and the reducer function that manages our state.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createSlice } from "@reduxjs/toolkit";

const usersSlice = createSlice({
  name: "users",
  initialState: {
    users: []
  },
  reducers: {
    getUsersSuccess: (state, action) =&amp;gt; {
      state.users = action.payload;
    },
  }
});

export const { getUsersSuccess } = usersSlice.actions;

export default usersSlice.reducer;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice how we seem to be "mutating" the state object, but indeed RTK takes care of &lt;em&gt;immutability&lt;/em&gt; behind the scene using &lt;a href="https://redux-toolkit.js.org/usage/immer-reducers" rel="noopener noreferrer"&gt;Immer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt; - Update Saga&lt;/p&gt;

&lt;p&gt;Now let's update our &lt;strong&gt;saga&lt;/strong&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 { call, put, takeEvery } from "redux-saga/effects";
import { getUsersSuccess } from "../features/userSlice";

function* getUsersRequest() {
    const users = yield call(() =&amp;gt; fetch('https://jsonplaceholder.typicode.com/users'));
    const formattedUsers = yield users.json(); 
    yield put(getUsersSuccess(formattedUsers)) 
}

export function* getUsersSaga(action) {
    yield takeEvery('users/getUsersFetch', getUsersRequest)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice in the &lt;strong&gt;getUsersSaga&lt;/strong&gt; function how we are using the action type which is generated based on the slice name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt; - Update configureStore&lt;/p&gt;

&lt;p&gt;Now we make a slight change in the &lt;strong&gt;configureStore&lt;/strong&gt; file and we are good to go!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {
    configureStore,
} from "@reduxjs/toolkit";
import createSagaMiddleware from "redux-saga";
import usersReducer from "../features/userSlice";


export default function configureStoreFunction() {
    const sagaMiddleware = createSagaMiddleware();

    return {
        ...configureStore({
            reducer: {
                users: usersReducer
            },
            middleware: [sagaMiddleware]
        }),
        runSaga: sagaMiddleware.run,
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we use the RTK configureStore instead of the &lt;em&gt;deprecated&lt;/em&gt; createStore that we used in &lt;strong&gt;plain Redux&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;configureStore&lt;/strong&gt; takes an object of reducer and middleware - reducer is an object of the generated reducers , and we add the saga instance into the middleware array.&lt;/p&gt;

&lt;p&gt;Another slight change in the imports of &lt;strong&gt;App.js&lt;/strong&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 { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { getUsersFetch } from "./features/userSlice";

function App() {
  const dispatch = useDispatch();
  const users = useSelector((state) =&amp;gt; state.users.users);
  useEffect(() =&amp;gt; {
    dispatch(getUsersFetch())
  }, [dispatch])
  return (
    &amp;lt;div className="App"&amp;gt;
      {users.map(user =&amp;gt; (&amp;lt;h2 key={Math.random()}&amp;gt;{user.name}&amp;lt;/h2&amp;gt;))}
    &amp;lt;/div&amp;gt;
  );
}
export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now it's time to explore &lt;strong&gt;RTK Query&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  RTK Query
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;We don't need to install any additional packages to use RTK Query.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt; - createApi&lt;/p&gt;

&lt;p&gt;Let's start by updating the &lt;strong&gt;usersSlice.js&lt;/strong&gt; with the code below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createApi } from '@reduxjs/toolkit/query/react'

export const apiSlice = createApi({
    reducerPath: 'UsersAPI'
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we are defining &lt;em&gt;usersApi&lt;/em&gt; using &lt;strong&gt;createApi&lt;/strong&gt; which is basically the core of &lt;em&gt;RTK Query's functionality&lt;/em&gt;, then we pass an object and set the &lt;em&gt;reducerPath&lt;/em&gt; to &lt;strong&gt;UsersAPI&lt;/strong&gt; to identify it.&lt;/p&gt;

&lt;p&gt;After that, we're going to set &lt;em&gt;baseQuery&lt;/em&gt;, which will essentially be our client with the API base URL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'

export const apiSlice = createApi({
    reducerPath: 'UsersAPI',
    baseQuery: fetchBaseQuery({ baseUrl: 'https://jsonplaceholder.typicode.com/' }),
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We then assign &lt;em&gt;endpoints&lt;/em&gt; which will contain the logic that specifies the actual paths we are getting (or modifying) the fetch data from, and then start defining the fields using &lt;strong&gt;builder&lt;/strong&gt; that we get from the arguments of &lt;em&gt;endpoints&lt;/em&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 { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'

export const apiSlice = createApi({
    reducerPath: 'UsersAPI',
    baseQuery: fetchBaseQuery({ baseUrl: 'https://jsonplaceholder.typicode.com/' }),
    endpoints: (builder) =&amp;gt; ({
        getUsers: builder.query({
            query: () =&amp;gt; 'users',
        }),
    })
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we set the basic query param that we are hitting, which would be &lt;strong&gt;users&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here we used the &lt;strong&gt;query&lt;/strong&gt; method because we are just getting data from the endpoint. If we are updating it, we would use &lt;strong&gt;mutation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That will auto-generate a hook based on the endpoint's name, so that would be &lt;strong&gt;useGetUsersQuery&lt;/strong&gt;, and then we are exporting it for later use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Full code:&lt;/strong&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 { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'

export const apiSlice = createApi({
    reducerPath: 'UsersAPI',
    baseQuery: fetchBaseQuery({ baseUrl: 'https://jsonplaceholder.typicode.com/' }),
    endpoints: (builder) =&amp;gt; ({
        getUsers: builder.query({
            query: () =&amp;gt; 'users',
        }),
    })
})

export const {
    useGetUsersQuery
} = apiSlice
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt; - ApiProvider&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Redux&lt;/strong&gt; requires us to wrap our app with a &lt;em&gt;Provider&lt;/em&gt; to which we pass our store.&lt;/p&gt;

&lt;p&gt;When we use &lt;strong&gt;RTK Query&lt;/strong&gt; for API access, we need to specify &lt;em&gt;ApiProvider&lt;/em&gt; and pass the &lt;strong&gt;apiSlice&lt;/strong&gt; into it.&lt;/p&gt;

&lt;p&gt;Let's update &lt;strong&gt;index.js&lt;/strong&gt; with the code below&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 from 'react';
import ReactDOM from 'react-dom/client';
import { ApiProvider } from "@reduxjs/toolkit/query/react";
import App from './App';
import { apiSlice } from "./features/userSlice";

const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(
  &amp;lt;React.StrictMode&amp;gt;
    &amp;lt;ApiProvider api={apiSlice}&amp;gt;
      &amp;lt;App /&amp;gt;
    &amp;lt;/ApiProvider&amp;gt;
  &amp;lt;/React.StrictMode&amp;gt;
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Let's now make use of what we have integrated&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Update &lt;strong&gt;App.js&lt;/strong&gt; with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useGetTodosQuery } from "./features/userSlice";

function App() {
  const {
    data: users,
    isLoading,
    isSuccess,
  } = useGetTodosQuery()  

  return (
    &amp;lt;div className="App"&amp;gt;
      {isLoading &amp;amp;&amp;amp; &amp;lt;span&amp;gt;Loading...&amp;lt;/span&amp;gt;}
      {isSuccess &amp;amp;&amp;amp; users.map(user =&amp;gt; (&amp;lt;h2 key={Math.random()}&amp;gt;{user.name}&amp;lt;/h2&amp;gt;))}
    &amp;lt;/div&amp;gt;
  );
}
export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;RTK query&lt;/strong&gt; provides us with some cool stuff that we usually track and write its logic ourselves.&lt;/p&gt;

&lt;p&gt;It encapsulates the entire data fetching process, so you can &lt;em&gt;catch errors&lt;/em&gt; and trace the request status if it's still &lt;em&gt;pending&lt;/em&gt; or &lt;em&gt;fulfilled&lt;/em&gt; using &lt;strong&gt;isLoading&lt;/strong&gt; without any handwritten boilerplate code that we usually do.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's now run the app and that's a wrap!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Full code can be found in the github repo &lt;a href="https://github.com/thisisgazzar/rtk-query-redux-saga" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion:
&lt;/h2&gt;

&lt;p&gt;As we can see, &lt;strong&gt;Redux Saga&lt;/strong&gt; is a powerful tool with &lt;strong&gt;many cool effects&lt;/strong&gt; built in, which saves you a lot of boilerplate code if you want to achieve what those effects offer.&lt;br&gt;
However, with &lt;strong&gt;RTK Query&lt;/strong&gt;, you can just kick off with a few lines of code &lt;em&gt;without&lt;/em&gt; installing any additional dependencies. It's also the &lt;strong&gt;recommended approach&lt;/strong&gt; by the Redux team for API interactions.&lt;br&gt;
Finally, you should carefully pick which one will fit better for your project, as it could be a pain in the ass if you decide to change it later.&lt;/p&gt;

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