<?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: Roselle Tabuena</title>
    <description>The latest articles on DEV Community by Roselle Tabuena (@iamdete).</description>
    <link>https://dev.to/iamdete</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%2F1267207%2F098ac59c-8760-4121-bd86-ed596c99f27a.JPG</url>
      <title>DEV Community: Roselle Tabuena</title>
      <link>https://dev.to/iamdete</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/iamdete"/>
    <language>en</language>
    <item>
      <title>From Zero to SAA-C03 Certified: How I Passed the AWS Certification on My First Attempt</title>
      <dc:creator>Roselle Tabuena</dc:creator>
      <pubDate>Sat, 27 Jul 2024 11:55:40 +0000</pubDate>
      <link>https://dev.to/iamdete/from-zero-to-saa-c03-certified-how-i-passed-the-aws-certification-on-my-first-attempt-20m6</link>
      <guid>https://dev.to/iamdete/from-zero-to-saa-c03-certified-how-i-passed-the-aws-certification-on-my-first-attempt-20m6</guid>
      <description>&lt;p&gt;When I started preparing for the SAA-C03 certification, I had zero to minimal AWS experience and often doubted if I could pass it without the recommended year of experience. Despite these doubts, I managed to pass the exam on my first attempt.&lt;/p&gt;

&lt;p&gt;To give you some context, here’s a brief background about me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I work full-time with a 9-hour shift.&lt;/li&gt;
&lt;li&gt;I’ve been a developer for nearly 3 years, with minimal AWS experience.&lt;/li&gt;
&lt;li&gt;My current role focuses mainly on front-end development.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Spent 6 months preparing, with plenty of breaks in between.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://learn.acloud.guru/" rel="noopener noreferrer"&gt;A Cloud Guru&lt;/a&gt; - Provided by my company, this platform was where I did most of my hands-on practice and experiments in the Playground. I took their SAA course there but didn't take it seriously, as I was primarily using Stéphane Maarek’s Ultimate AWS SAA-C03 course.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.udemy.com/course/aws-certified-solutions-architect-associate-saa-c03/" rel="noopener noreferrer"&gt;Ultimate AWS Certified Solutions Architect Associate SAA-C03&lt;/a&gt; -I think this course is sufficient to pass the SAA exam, but for a deeper dive into AWS, I recommend Adrian Cantrill's  &lt;a href="https://learn.cantrill.io/p/aws-certified-solutions-architect-associate-saa-c03" rel="noopener noreferrer"&gt;SAA-C03 course&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://portal.tutorialsdojo.com/courses/aws-certified-solutions-architect-associate-practice-exams/?_gl=1*1dm4q6a*_ga*MTI2OTg3MTY5NC4xNjk1OTA5MTU4*_ga_L96TFJ1R9K*MTcyMjA3NjE5Ni4xMS4wLjE3MjIwNzYxOTYuMC4wLjA." rel="noopener noreferrer"&gt;Tutorials Dojo&lt;/a&gt; - This practice exam is a must! Their review mode works like a charm. If I hadn’t taken their exam, I’m sure I would have failed.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Study Routine and Strategies:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Taking notes is not for me. Instead, I focused on understanding the concepts and doing hands-on practice. While this approach helped me grasp the material, it sometimes led to challenges remembering specific features of services since I'm not taking notes.&lt;/p&gt;

&lt;p&gt;My study routine was flexible due to my unpredictable schedule. I didn’t force myself to study if I wasn’t in the mood, which helped keep stress levels low. However, 1 week before the exam, I began to doubt myself and I started to read a lot of others' experience in Reddit in SAA exam. I think I lost a lot of time by just worrying.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exam Day Experience:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I chose to take the exam at a testing center to avoid the headaches potential issues with online testing, as some exam takers have had negative experiences with online exams.&lt;/p&gt;

&lt;p&gt;I was glad that two dogs greeted me when I arrived at the testing center. I was the only one taking the exam. I filled out the form and then surrendered all my belongings, which were placed in a locker.&lt;/p&gt;

&lt;p&gt;While others said that the questions were similar to those in Tutorials Dojo, but I found them less wordy and easier. Still, I struggled with questions about services I wasn’t familiar with. I marked 10 questions for review and I think there are total of 15 questions that I'm unfamiliar with. &lt;/p&gt;

&lt;p&gt;I focused too much in harder topics like VPC, Security and Data Migration that I end up forgetting other features of services and lowering less than my practice exams. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My exam results:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Average in Practice Exam Review Mode is 80% &lt;br&gt;
Average in Practice Exam Timed Mode is 85%-90%&lt;br&gt;
Actual score is 776/1000 &lt;/p&gt;

&lt;p&gt;With the SAA-C03 certification behind me, I’m excited to dive into hands-on projects and put my AWS knowledge to practical use. I’m grateful for the support and resources that helped me along the way.&lt;/p&gt;

</description>
      <category>learning</category>
      <category>career</category>
    </item>
    <item>
      <title>Building CRUD with ES6 JavaScript and Local Storage</title>
      <dc:creator>Roselle Tabuena</dc:creator>
      <pubDate>Sun, 17 Mar 2024 04:38:58 +0000</pubDate>
      <link>https://dev.to/iamdete/building-crud-with-es6-javascript-and-local-storage-1ijd</link>
      <guid>https://dev.to/iamdete/building-crud-with-es6-javascript-and-local-storage-1ijd</guid>
      <description>&lt;p&gt;In this tutorial, we'll learn how to create a basic CRUD application using JavaScript ES6 and Local Storage. By the end of this guide, you'll know how to implement CRUD with local storage in your own projects. Let's get code together.&lt;/p&gt;

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

&lt;p&gt;Basic knowledge in the following: &lt;br&gt;
HTML &lt;br&gt;
Javascript&lt;br&gt;
CSS&lt;/p&gt;
&lt;h3&gt;
  
  
  Set up
&lt;/h3&gt;
&lt;h4&gt;
  
  
  File Structure:
&lt;/h4&gt;

&lt;p&gt;Set up your file first with your choosen IDE.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;index.css
index.html 
index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Inital Code
&lt;/h3&gt;

&lt;h4&gt;
  
  
  CSS
&lt;/h4&gt;

&lt;p&gt;Copy this &lt;a href="https://github.com/roselletabuena/CRUD-javascript-localStorage/blob/start-activity/index.css" rel="noopener noreferrer"&gt;CSS code&lt;/a&gt; into your index.css.&lt;/p&gt;

&lt;h4&gt;
  
  
  HTML
&lt;/h4&gt;

&lt;p&gt;Copy this &lt;a href="https://github.com/roselletabuena/CRUD-javascript-localStorage/blob/start-activity/index.html" rel="noopener noreferrer"&gt;index.html&lt;/a&gt; into your index.css.&lt;/p&gt;

&lt;h4&gt;
  
  
  JavaScript
&lt;/h4&gt;

&lt;p&gt;We're utilizing the dialog as our modal, so we don't have to code the modal manually. Simply copy the code below into your 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;const dialog = document.querySelector('dialog');
const showButton = document.querySelector('#btn-add');
const closeButton = document.querySelector('#btn-close');

showButton.addEventListener('click', () =&amp;gt; {
  dialog.showModal();
});

closeButton.addEventListener('click', () =&amp;gt; {
  dialog.close();
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Exploring our Initial App:
&lt;/h3&gt;

&lt;p&gt;Since our focus is to build a small application using JavaScript and localStorage as our database, we'll skip the HTML part and dive directly into explaining how we will build the functionality.&lt;/p&gt;

&lt;p&gt;Let's explore our app first. Click the "Add Student" and see the form with fields name, email and course. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzysd3nkh6vgjxfcu8g0r.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzysd3nkh6vgjxfcu8g0r.PNG" alt="html form with name, email, course fields" width="334" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let's move on to the table display. You'll notice the following columns: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ID&lt;/strong&gt;: Unique identification of the student data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name, Email, Course&lt;/strong&gt;: Personal Info of the student&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Actions&lt;/strong&gt;: Perform Edit and Delete record in this columns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since you already know what our app. Let's start to code. &lt;/p&gt;

&lt;h4&gt;
  
  
  START
&lt;/h4&gt;

&lt;p&gt;Copy this code first; we'll use it later. Make sure it's positioned below your main code for better organization.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* Modal dialog code */

/* put your code here... */


// utilities 
function populateTable() {
  let tableRow = '';
  getStudentList().forEach((student) =&amp;gt; {
    tableRow += tableRowHTML(student);
  });

  table.innerHTML = tableRow;
}

const generateRandomId = () =&amp;gt; Math.floor(Math.random() * 99999);

const formDataToObject = (formData) =&amp;gt; {
  const object = {};
  formData.forEach((value, key) =&amp;gt; {
    object[key] = value;
  });
  return object;
};

function resetForm() {
  document.querySelector('#student-id').value = '';
  studentForm.reset();
}

function tableRowHTML(student) {
  return `&amp;lt;tr id='std_${student.id}'&amp;gt;
            &amp;lt;td&amp;gt;${student.id}&amp;lt;/td&amp;gt;
            &amp;lt;td&amp;gt;${student.name}&amp;lt;/td&amp;gt;
            &amp;lt;td&amp;gt;${student.email}&amp;lt;/td&amp;gt;
            &amp;lt;td&amp;gt;${student.course}&amp;lt;/td&amp;gt;
            &amp;lt;td class="actions"&amp;gt;
            &amp;lt;button student-id="${student.id}" action-type="edit" class="edit-btn"&amp;gt;Edit&amp;lt;/button&amp;gt;
            &amp;lt;button student-id="${student.id}" action-type="delete" class="delete-btn"&amp;gt;Delete&amp;lt;/button&amp;gt;
            &amp;lt;/td&amp;gt;
        &amp;lt;/tr&amp;gt;`;
}

function getStudentList() {
  return JSON.parse(localStorage.getItem('studentList')) || [];
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Declarations:&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;// dialog code 

const studentForm = document.getElementById('student-form');
const table = document.querySelector('table tbody');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Getting the studentForm and table from our DOM, we'll add event listeners later.&lt;/p&gt;

&lt;h3&gt;
  
  
  CREATE
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Add Form Function&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 addForm = (formData) =&amp;gt; {
  formData.append('id', generateRandomId());

  const student = formDataToObject(formData);
  studentList.push(student);

  localStorage.setItem('studentList', JSON.stringify(studentList));

  const newRow = table.insertRow(-1);

  newRow.id = 'std_' + student.id;
  newRow.innerHTML = tableRowHTML(student);
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function above, addForm, adds new student data to the application. It generates a random ID for the student, appends it to the form data, and converts the form data into a student object. The student object is then added to the studentList array, which is stored in local storage. Additionally, a new row is inserted into the HTML table to display the new student's information. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FORM SUBMISSION:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;addSubmit&lt;/code&gt; function to the form.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;studentForm.addEventListener('submit', (event) =&amp;gt; {
  event.preventDefault();

  const formData = new FormData(studentForm);

  addForm(formData);

  resetForm();
  dialog.close();
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To test if it's working, go to the localStorage in the inspect tab under the "Application" section, and check if the data has been added successfully. If it's working, proceed to the next step.&lt;/p&gt;

&lt;h3&gt;
  
  
  READ
&lt;/h3&gt;

&lt;p&gt;We have a function called &lt;code&gt;populateTable&lt;/code&gt;. Its purpose is to display the existing data in the localStorage during the first load of our application. It retrieves data from the &lt;code&gt;getStudentList()&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;Call &lt;strong&gt;&lt;code&gt;populateTable()&lt;/code&gt;&lt;/strong&gt; after all the our variable declarations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const studentForm = document.getElementById('student-form');
const table = document.querySelector('table tbody');

populateTable(); // add this code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will display the student info on the first load of the application if there's an existing data. &lt;/p&gt;

&lt;h3&gt;
  
  
  UPDATE
&lt;/h3&gt;

&lt;p&gt;Displaying Student Information in a Modal for Editing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;table.addEventListener('click', (event) =&amp;gt; {
  const target = event.target;
  const id = target.getAttribute('student-id');

  if (target.classList.contains('edit-btn')) {
    dialog.showModal();

    const student = getStudentList().find((student) =&amp;gt; id == student.id);

    document.getElementById('student-id').value = student.id;
    document.getElementById('name').value = student.name;
    document.getElementById('email').value = student.email;
    document.getElementById('course').value = student.course;
  }
});

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

&lt;/div&gt;



&lt;p&gt;The code snippet above enables editing of student details directly within the table. When a user clicks an &lt;code&gt;edit&lt;/code&gt; button in a row, it triggers a dialog displaying the student's information fetched from the &lt;code&gt;getStudentList()&lt;/code&gt; function based on the student ID. The data retrieved is then utilized to update the input values for each field using &lt;code&gt;document.getElementById('input-id')&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  EDIT
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const editForm = (formData) =&amp;gt; {
  const studentForm = formDataToObject(formData);
  const studentList = getStudentList();

  const studentIndex = getStudentList().findIndex(
    (student) =&amp;gt; studentForm.id == student.id
  );

  if (studentIndex == -1) return;

  studentList[studentIndex] = {
    ...studentList[studentIndex],
    ...studentForm,
  };

  localStorage.setItem('studentList', JSON.stringify(studentList));

  document.querySelector('#std_' + studentForm.id).innerHTML =
    tableRowHTML(studentForm);
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;editForm&lt;/code&gt; function edits student details by updating the student list with new form data and saving it back to local storage. It first converts form data to an object, retrieves the student list, finds the index of the student being edited, updates their information using &lt;code&gt;tableRowHTML&lt;/code&gt;, and then updates the corresponding row in the HTML table with the new data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FORM SUBMISSION:&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;studentForm.addEventListener('submit', (event) =&amp;gt; {
  event.preventDefault();

  const formData = new FormData(studentForm);

  const isEditMode = formData.get('id') != ''; 

  if (isEditMode) {
    editForm(formData);
  } else {
    addForm(formData);
  }

  resetForm();
  dialog.close();
});

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

&lt;/div&gt;



&lt;p&gt;We've improved our form to handle both updating and adding student data using just one form. Now, if the form has an &lt;code&gt;id&lt;/code&gt; field, it's for editing, so we call the editForm function. Otherwise, if there's no &lt;code&gt;id&lt;/code&gt; field, it's for adding new data, so we call the addForm function. This tweak makes it easier for users to manage student information in our application.&lt;/p&gt;

&lt;h3&gt;
  
  
  DELETE
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;table.addEventListener('click', (event) =&amp;gt; {
  const target = event.target;
  const id = target.getAttribute('student-id');

  if (target.classList.contains('edit-btn')) {... code for edit ...}
  } else if (target.classList.contains('delete-btn')) {
    const row = target.parentNode.parentNode;
    const newStudentList = getStudentList().filter(
      (student) =&amp;gt; id != student.id
    );

    document.querySelector('table').deleteRow(row.rowIndex);

    localStorage.setItem('studentList', JSON.stringify(newStudentList));
}); 

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

&lt;/div&gt;



&lt;p&gt;Let's modify our code for &lt;code&gt;table.addEventListener()&lt;/code&gt;. We've added a new condition for the delete button if it's triggered. Then, we'll retrieve the row of the table using &lt;code&gt;target.parentNode.parentNode&lt;/code&gt;. Afterward, we'll use filter to return a new list without the student ID of the selected student item in the table. Following this, we'll delete the selected row using &lt;code&gt;deleteRow&lt;/code&gt;. Lastly, we'll update the new localStorage with our new student list. This functionality allows our users to delete user records directly from the table interface while keeping the data synchronized.&lt;/p&gt;

&lt;h3&gt;
  
  
  END OF CODE
&lt;/h3&gt;

&lt;p&gt;That's all for the CRUD functionality. I hope you found this tutorial helpful. If you encounter any issues, feel free to refer to our source code for comparison. I also include the demo link below so you can test the application yourself. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://javascript-es6-crud.netlify.app/" rel="noopener noreferrer"&gt;CLICK HERE FOR DEMO&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/roselletabuena/CRUD-javascript-localStorage/blob/start-activity/index.css" rel="noopener noreferrer"&gt;INITAL CODE&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/roselletabuena/CRUD-javascript-localStorage/blob/main/index.css" rel="noopener noreferrer"&gt;CRUD SOURCE CODE&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thank you for reading my blog.&lt;/p&gt;

&lt;p&gt;If you have any suggestions or corrections, please leave a comment below. I'll gladly respond and consider your input.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How to Implement Modal using React Router v6</title>
      <dc:creator>Roselle Tabuena</dc:creator>
      <pubDate>Sat, 27 Jan 2024 17:16:05 +0000</pubDate>
      <link>https://dev.to/iamdete/how-to-implement-modal-using-react-router-v6-1egk</link>
      <guid>https://dev.to/iamdete/how-to-implement-modal-using-react-router-v6-1egk</guid>
      <description>&lt;p&gt;Hello! I've been searching how to implement Modal in React Router v6, but unfortunately, the results that I found didn't match my needs. The tutorial blogs that I came across were using &lt;code&gt;JSX Routes&lt;/code&gt; and I'm using &lt;code&gt;createBrowserRouter&lt;/code&gt; to manage my history stack. After some searching and trying to make it work, I finally got it to work. 🙃&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F26lpqdn9xqmkuseom5wd.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F26lpqdn9xqmkuseom5wd.gif" alt="react-router-modal-sample-v5"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to achieve the sample GIF above but in React V6 and you're using &lt;code&gt;createBrowserRouter&lt;/code&gt;, then this tutorial is for you ✨&lt;/p&gt;

&lt;p&gt;Here's how I did it. 😄&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fi15y39x9vdfoaonzoats.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fi15y39x9vdfoaonzoats.gif" alt="react-router-modal-sample"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The tutorial below will be just focusing on implementing modal it doesn't have navbar like in the image above. &lt;/p&gt;

&lt;h3&gt;
  
  
  START
&lt;/h3&gt;

&lt;p&gt;First things first, You need to create react app and install the &lt;code&gt;react-router-dom&lt;/code&gt; and run &lt;code&gt;npm install&lt;/code&gt; to start.&lt;/p&gt;

&lt;p&gt;Let's start with the folder structure. Simply copy the layout of my files and folders provided below:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/src
  /components
   Modal.js
  /data
   dummy-data.js
  /pages
   Gallery.jsx
  App.jsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  dummy-data.js
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const images = [
  {
    id: 1,
    thumbnail:
      'https://images.unsplash.com/photo-1682685797886-79020b7462a4?w=500&amp;amp;auto=format&amp;amp;fit=crop&amp;amp;q=60&amp;amp;ixlib=rb-4.0.3&amp;amp;ixid=M3wxMjA3fDF8MHxlZGl0b3JpYWwtZmVlZHwxfHx8ZW58MHx8fHx8',
    fullSize:
      'https://images.unsplash.com/photo-1682685797886-79020b7462a4?q=80&amp;amp;w=2070&amp;amp;auto=format&amp;amp;fit=crop&amp;amp;ixlib=rb-4.0.3&amp;amp;ixid=M3wxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
    details: 'Details about Image 1',
  },
  {
    id: 2,
    fullSize:
      'https://images.unsplash.com/photo-1706028024882-0b972506d02d?q=80&amp;amp;w=1964&amp;amp;auto=format&amp;amp;fit=crop&amp;amp;ixlib=rb-4.0.3&amp;amp;ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
    thumbnail:
      'https://images.unsplash.com/photo-1706028024882-0b972506d02d?w=500&amp;amp;auto=format&amp;amp;fit=crop&amp;amp;q=60&amp;amp;ixlib=rb-4.0.3&amp;amp;ixid=M3wxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwzfHx8ZW58MHx8fHx8',
    details: 'Details about Image 2',
  },
];

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

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;dummy-data.js&lt;/code&gt;contains a array object that will be use as our dummy data. The &lt;code&gt;id&lt;/code&gt; will be a unique identifier for our image it will be use later to get the image details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modal.jsx
&lt;/h2&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useEffect, useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { images } from '../data/dummy-data';

const Modal = () =&amp;gt; {
  const { id: imageId } = useParams();
  const navigate = useNavigate();

  const [imageData, setImageData] = useState(null);

  useEffect(() =&amp;gt; {
    const image = images.find(({ id }) =&amp;gt; imageId == id);

    setImageData(image);
  }, [imageId]);

  const handleOnClose = () =&amp;gt; {
    navigate('/');
  };

  return (
    &amp;lt;&amp;gt;
      {imageData &amp;amp;&amp;amp; (
        &amp;lt;div className="modal"&amp;gt;
          &amp;lt;div className="modal-content"&amp;gt;
            &amp;lt;img src={imageData.fullSize} alt="Full Size" /&amp;gt;
            &amp;lt;p&amp;gt;{imageData.details}&amp;lt;/p&amp;gt;
            &amp;lt;button onClick={handleOnClose}&amp;gt;Close&amp;lt;/button&amp;gt;
          &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
      )}
    &amp;lt;/&amp;gt;
  );
};

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

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;Modal.jsx&lt;/code&gt; is a functional component will be used to as our pop up modal for viewing details of specific image. &lt;/p&gt;

&lt;h4&gt;
  
  
  Variable Declarations:
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;imageId&lt;/code&gt;: extracts the id from the route using &lt;code&gt;useParams()&lt;/code&gt; This is the unique identifier for the image being displayed in the modal. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;navigate&lt;/code&gt; Provides a function to navigate between pages using useNavigate().&lt;/p&gt;

&lt;h4&gt;
  
  
  State Management:
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;imageData&lt;/code&gt; represents the state for holding information about the selected image. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;useEffect&lt;/code&gt; is used to fetch the details of the image when the component mounts or when the &lt;code&gt;imageId&lt;/code&gt; changes. It finds the corresponsing image in the &lt;code&gt;images&lt;/code&gt; array object (imported from the dummy-data).&lt;/p&gt;

&lt;h4&gt;
  
  
  Close Modal Function:
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;handleOnClose&lt;/code&gt; defines a function to clode the modal by navigating back to the root path ('/) using the &lt;code&gt;navigate&lt;/code&gt;function.&lt;/p&gt;

&lt;h4&gt;
  
  
  Render Modal:
&lt;/h4&gt;

&lt;p&gt;The component renders a modal only if &lt;code&gt;imageData&lt;/code&gt; is truthy (i.e., an image is found). Inside the modal, it displays the full-size image, additional details, and close button.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gallery.jsx
&lt;/h2&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import { useNavigate } from 'react-router-dom';
import { images } from '../data/dummy-data';
import Modal from '../components/Modal';

const Gallery = () =&amp;gt; {
  const navigate = useNavigate();

  const viewImage = (image) =&amp;gt; {
    const id = image.id;
    navigate('/view/' + id);
  };

  return (
    &amp;lt;div className="gallery"&amp;gt;
      {images.map((image, index) =&amp;gt; (
        &amp;lt;button
          key={image.id}
          className="gallery-item"
          onClick={() =&amp;gt; viewImage(image)}
        &amp;gt;
          &amp;lt;img src={image.thumbnail} alt={`Thumbnail ${index + 1}`} /&amp;gt;
        &amp;lt;/button&amp;gt;
      ))}

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

export default Gallery;

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

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;Gallery.jsx&lt;/code&gt; is responsible for rendering a gallery of images with thumbnail previews. Inside the component, it maps over the images array object from dummy data. Each button has a click event handler &lt;code&gt;(onClick)&lt;/code&gt; that calls the viewImage function with the corresponding image.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;viewImage&lt;/code&gt; function takes an image object parameter based on the thumbnail click, and it extracts the id property from the image object. It then navigates to the route view/:id.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Modal&lt;/code&gt; component is rendered at the end of the &lt;code&gt;Gallery&lt;/code&gt; component. It is included to provide the modal functionality for viewing detailed information about a selected image.&lt;/p&gt;

&lt;h2&gt;
  
  
  App.jsx
&lt;/h2&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import Gallery from './pages/gallery';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';

const router = createBrowserRouter([
  {
    path: '/',
    element: &amp;lt;Gallery /&amp;gt;,
    children: [
      {
        path: 'view/:id',
        element: null,
      },
    ],
  },
]);

function App() {
  return (
    &amp;lt;React.StrictMode&amp;gt;
      &amp;lt;RouterProvider router={router} /&amp;gt;
    &amp;lt;/React.StrictMode&amp;gt;
  );
}

export default App;

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

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;createBrowserRouter&lt;/code&gt; is the recommended router for all React Router web projects. It uses DOM History API to update the URL and manage the history stack.&lt;/p&gt;

&lt;p&gt;The main router for the code above is specified with &lt;code&gt;path: '/'&lt;/code&gt; and is set to render the &lt;code&gt;Gallery&lt;/code&gt;component. &lt;/p&gt;

&lt;p&gt;Additionally, there's a child route defines with &lt;code&gt;path: 'view/:id'&lt;/code&gt; but the &lt;code&gt;element&lt;/code&gt; associated with it is set to &lt;code&gt;null&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;RouterProvider&lt;/code&gt; component is used to provide the router instance (&lt;code&gt;router&lt;/code&gt;) to the entire React component tree. This is crucial for enabling the routing functionality.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fmexotg64trztuaydfe8g.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fmexotg64trztuaydfe8g.gif" alt="react-router-modal-sample"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  End of Code.
&lt;/h3&gt;




&lt;h3&gt;
  
  
  Explanation Summary:
&lt;/h3&gt;

&lt;p&gt;We have an index parent route and it has children route &lt;code&gt;view/:id&lt;/code&gt; that renders null element. If we navigate to this routes, the parent element will retain its current position. The reason for this is that we don't have an &lt;code&gt;&amp;lt;Outlet /&amp;gt;&lt;/code&gt; to render the children of the parent route. So, it will just stay at the location where we trigger the navigation. The reason why the Modal is showing because we have a &lt;code&gt;useEffect&lt;/code&gt; that triggers when the &lt;code&gt;gallery/:id&lt;/code&gt; changes. It will only trigger if we click the thumbnails that triggers to update the URL. &lt;/p&gt;

&lt;p&gt;That's all! I hope this was helpful. If you have any questions, feel free to ask. Thanks for reading!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://react-router-modal.netlify.app/" rel="noopener noreferrer"&gt;LIVE DEMO&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/roselletabuena/react-router-modal" rel="noopener noreferrer"&gt;Source Code With Navbar&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/roselletabuena/react-router-modal/tree/modal-only" rel="noopener noreferrer"&gt;Source Code Modal Only&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>reactjsdevelopment</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
