<?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: Raymond Luu</title>
    <description>The latest articles on DEV Community by Raymond Luu (@raymondluudev).</description>
    <link>https://dev.to/raymondluudev</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%2F894708%2F0abe38ac-2d7b-46ce-b111-b24352edd234.png</url>
      <title>DEV Community: Raymond Luu</title>
      <link>https://dev.to/raymondluudev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/raymondluudev"/>
    <language>en</language>
    <item>
      <title>Ready for a "Remix" on React?</title>
      <dc:creator>Raymond Luu</dc:creator>
      <pubDate>Tue, 20 Sep 2022 17:35:43 +0000</pubDate>
      <link>https://dev.to/devsatasurion/ready-for-a-remix-on-react-4l8a</link>
      <guid>https://dev.to/devsatasurion/ready-for-a-remix-on-react-4l8a</guid>
      <description>&lt;p&gt;You might be curious about the title and think that this blog post is about React… well sort of. This will be about a new framework I am learning called Remix, which under the hood includes React. Check it out &lt;a href="https://remix.run/" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have been working on React for the past 4 years and lately I have been hearing a lot about these newer frameworks like Next.js and Remix. It got me thinking about what these frameworks might offer, plus who wouldn’t want to learn new things in the React ecosystem? I certainly would like to!&lt;/p&gt;

&lt;p&gt;My goal here is not to repeat the &lt;a href="https://remix.run/docs/en/v1/tutorials/blog" rel="noopener noreferrer"&gt;quick start guide&lt;/a&gt; that they provide but to highlight some of the cool things that I learned from following it (they did a great job in guiding readers through the cool features that Remix has). Getting started was super easy! I think it literally took me 5-10mins just to get things running and start coding! It is crazy how fast it is these days. Here is a link to the &lt;a href="https://egghead.io/lessons/remix-create-a-new-remix-project-using-the-remix-create-cli" rel="noopener noreferrer"&gt;video&lt;/a&gt; tutorial if you prefer that instead w/ Instructor Kent C. Dodds!&lt;/p&gt;

&lt;p&gt;I have done a small bit of diving into Next.js but this isn't really about a comparison between the two. It is mainly to give you an introduction into what Remix is from what I have learned! Enough with the intro and let’s dive right in and talk about all the cool things that Remix offers.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I liked about Remix
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Easy setup!&lt;/li&gt;
&lt;li&gt;Full stack!&lt;/li&gt;
&lt;li&gt;Remix has great documentation&lt;/li&gt;
&lt;li&gt;Routing is built into project structure&lt;/li&gt;
&lt;li&gt;The code to write for loading data is simple&lt;/li&gt;
&lt;li&gt;Creating forms with Remix Actions looks clean&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I will break down some of these bullet points down below.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let's start remixing
&lt;/h3&gt;

&lt;p&gt;Getting started is super quick and easy!&lt;/p&gt;

&lt;p&gt;There are some prerequisites so make sure you are up to date on some of the versions for things like Node and NPM.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-remix --template remix-run/indie-stack blog-tutorial
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The above command will get you to set up with their template and it includes a bunch of code to get you started. You can also follow along with their quick start guide; however, if you want to have a clean and minimal project with none of that just run this (replacing my-project-name w/ the name you desire):&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-remix my-project-name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then to start the dev server you just run the following:&lt;/p&gt;

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

&lt;/div&gt;

&lt;p&gt;Easy as that. Now you are ready to code! I do recommend starting with the template though. I did that through my first attempt to better understand the concepts and went back again working through a minimal project to play around with features that I was curious about outside of their blogging tutorial.&lt;/p&gt;

&lt;h3&gt;
  
  
  Frontend and Backend?
&lt;/h3&gt;

&lt;p&gt;React is all frontend JavaScript. The server serves a single index.html file with all the JavaScript for your application bundled together. All functionality exists in the JavaScript code in the browser.&lt;/p&gt;

&lt;p&gt;However, Remix is different. Remix is a full stack framework. Node.js on the backend and React on the frontend. Most of the components you will build are compiled on the server then served to the client and rendered onto the screen. Minimal JavaScript is sent to the client unless you want to include a few React functionalities, which we will talk about later.&lt;/p&gt;

&lt;p&gt;The idea of being full stack really reminds me of the monolithic architecture that I was so used to learning back when I first started my software development career (for about a few months until React skyrocketed into popularity). I was specifically working with a &lt;a href="https://en.wikipedia.org/wiki/LAMP_(software_bundle)" rel="noopener noreferrer"&gt;LAMP&lt;/a&gt; stack back then. PHP for the server-side code that served all the pages along with any HTML/CSS/JavaScript that was needed for that page of the app. There was no API either. If the UI needed some data from the DB, it would call your PHP server code to fetch the data and serve the page with it.&lt;/p&gt;

&lt;p&gt;Another stack I worked with was the &lt;a href="https://en.wikipedia.org/wiki/MEAN_(solution_stack)" rel="noopener noreferrer"&gt;MEAN&lt;/a&gt; stack. Remix to me is an evolved form of that. With the MEAN stack you had your Angular application served from one server while your Node.js was on a separate server acting as your API and bridge to your DB. That was full stack JavaScript but with JSON communication between two servers (one for UI and the other for API). What Remix does is takes us back to that monolithic architecture. One server to serve your UI to the client while providing it any necessary data from the DB.&lt;/p&gt;

&lt;p&gt;Both MEAN stack and Remix are full stack JavaScript. Only difference is MEAN stack has two servers with JSON data layer for communication while Remix uses a single server for both the frontend and backend. This makes it feel like the lines get blurred between client and server if you worked on stacks like MEAN. However, it’s like the LAMP stack where all your code lives on the server and that serves the client what it needs to see depending on what part of the application you are using. Remix is very similar to Next.js in that sense as well! If you are interested in the maintainer's take on the differences check out this &lt;a href="https://remix.run/blog/remix-vs-next" rel="noopener noreferrer"&gt;article&lt;/a&gt;! Now let’s look at how data loading works.&lt;/p&gt;

&lt;h3&gt;
  
  
  Loading data with Remix
&lt;/h3&gt;

&lt;p&gt;Data loading is built into the Remix framework! Let's look at how that works.&lt;/p&gt;

&lt;center&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%2Fjhaa7i0ehn6ddtgw8vif.png" 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%2Fjhaa7i0ehn6ddtgw8vif.png" alt="dashboard-loader"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;
In the above image we are mocking some data.
&lt;/b&gt;
&lt;/p&gt;
&lt;/center&gt;

&lt;p&gt;First off, I did make a comment in my code that we could move some of the data handling to a separate file. Separation of concerns here is great but it is included in this file to easily see everything in one place.&lt;/p&gt;

&lt;p&gt;Remix will understand this loader function as a way for the UI to load the data. "Loaders" are the auto wired backend "API" connection for the components. In this case we just provide a mock object of an array of books with “id” and “title”. Typically, in a real-life scenario we would make an API call here to get our data or in Remix's case we call the DB layer to fetch the data we need for this view.&lt;/p&gt;

&lt;center&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%2Fgwhzh53j4gu61npos0q3.png" 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%2Fgwhzh53j4gu61npos0q3.png" alt="dashboard-render"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;
This above code shows the main dashboard component.
&lt;/b&gt;
&lt;/p&gt;
&lt;/center&gt;

&lt;p&gt;Line 34 is where you will see the usage of that data from our loader above, then we return the HTML that includes the data we used to generate a list of that data. The “Links” are for routing which we will talk about later.&lt;/p&gt;

&lt;center&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%2Fbz3yfvna7stx9ugnk3cc.png" 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%2Fbz3yfvna7stx9ugnk3cc.png" alt="dashboard-imports"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;
The above picture shows the imports I used.
&lt;/b&gt;
&lt;/p&gt;
&lt;/center&gt;

&lt;p&gt;For data loading we care about “json” from “@remix-run/node” and “useLoaderData” from “@remix-run/react”. The imports really help differentiate which side of the stack they are from. Node meaning it is from backend and React meaning it is from frontend.&lt;/p&gt;

&lt;center&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%2Fbh21hwqax1pfjcik0xau.png" 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%2Fbh21hwqax1pfjcik0xau.png" alt="dashboard-component"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;
Here is a look at the full code for the Dashboard component I built above.
&lt;/b&gt;
&lt;/p&gt;
&lt;/center&gt;

&lt;p&gt;Does that not look simply easy? Obviously one thing to note is that we would want to replace the mock json with actual data from a DB. The tutorial shows you how if you are interested. They use Prisma as their ORM of choice. Let's move onto routing!&lt;/p&gt;

&lt;h3&gt;
  
  
  Routing
&lt;/h3&gt;

&lt;p&gt;For me personally, the routing took a bit of time to understand and to get used to. When I initially learned Next.js I saw this similar pattern where the folder structure dictates your routing. The folder structure is a very nice feature because you can just look at it and see which component is rendered at which route. With React Router you had a separate file defining those routes and components that rendered at each. You don't have to worry about that single definition file here though.&lt;/p&gt;

&lt;center&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%2Fdh7axavjdduokdtzggm5.png" 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%2Fdh7axavjdduokdtzggm5.png" alt="routing-example-one"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;
For an example of routing the above index.tsx file renders your component for the root of your app (localhost:3000/).
&lt;/b&gt;
&lt;/p&gt;
&lt;/center&gt;

&lt;center&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%2F5u5b9tn0tt09cml82ipr.png" 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%2F5u5b9tn0tt09cml82ipr.png" alt="routing-example-two"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;
In this example we see the file /routes/dashboard/index.tsx which will render your dashboard component at localhost:3000/dashboard
&lt;/b&gt;
&lt;/p&gt;
&lt;/center&gt;

&lt;center&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%2F3z7ig6vsey75gxn288fa.png" 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%2F3z7ig6vsey75gxn288fa.png" alt="routing-example-three"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;
For an example of a route slug, you will notice in the image above the file named "$slug.tsx"
&lt;/b&gt;
&lt;/p&gt;
&lt;/center&gt;

&lt;p&gt;This is considered a route param. To navigate to the component being rendered at this route we use “localhost:3000/book/1”. Then in your code you will have access to the property “slug” which is assigned the value 1 based on the “/1” part of the route. You don't have to be restricted to using “slug” it can be anything you choose. You could in fact rename the file to “$bookId.tsx” and in your code you will have access to “bookId” and the value 1 assigned to it.&lt;/p&gt;

&lt;p&gt;The below image shows what the component looks like. You can see it uses the loader function and has params as an input which we return it in a JSON format. Then in the component we can access it with “useLoaderData”.&lt;/p&gt;

&lt;center&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%2F04nrtwyzzijnchg3jxpy.png" 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%2F04nrtwyzzijnchg3jxpy.png" alt="routing-example-three-code"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;/center&gt;

&lt;p&gt;You can get even fancier with Outlets. Remix provides a way for you to render different child routes. For example, if you wanted to do something like “/dashboard/admin” and “/dashboard/” to have different components for normal users vs admin users you can! The component being rendered at this route “/dashboard/” can include an “Outlet” which by default renders your dashboard for normal users. It can as well render your admin component at “/dashboard/admin”. &lt;/p&gt;

&lt;p&gt;Here is the add-comment component example:&lt;/p&gt;

&lt;center&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%2F9eq7dgtd4l7bcdrk324d.png" 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%2F9eq7dgtd4l7bcdrk324d.png" alt="routing-outlets-example"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;
File structure for "add-comment" component using Outlet.
&lt;/b&gt;
&lt;/p&gt;
&lt;/center&gt;

&lt;center&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%2Fjje17tk7m3bkobw9vvxl.png" 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%2Fjje17tk7m3bkobw9vvxl.png" alt="routing-outlets-example-code"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;
Code for the "add-comment" component.
&lt;/b&gt;
&lt;/p&gt;
&lt;/center&gt;

&lt;p&gt;Take notice of the Outlet usage in the code as well as the file structure. You will see that under "/dashboard" we have "/add-comment/" folder as well as "add-comment.tsx" file. Then under the "/add-comment/" folder we have "index.tsx" and "new.tsx" file.&lt;/p&gt;

&lt;p&gt;The URL "localhost:3000/dashboard/add-comment" will render our "add-comment.tsx" component while also rendering the "/add-comment/index.tsx" component within the Outlet. However, if you navigate to the URL "localhost:3000/dashboard/add-comment/new" Then the Outlet will update and render the "/add-comment/new.tsx" component instead. Yeah, I couldn't even wrap my brain around that at first. This might take some getting used to but eventually it will make sense. Hopefully the below snippet will help you visualize it better.&lt;/p&gt;

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

URL -- localhost:3000/dashboard/add-comment
renders -- "add-comment.tsx"
Outlet renders -- "/add-comment/index.tsx"


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

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

URL -- localhost:3000/dashboard/add-comment/new
renders -- "add-comment.tsx"
Outlet renders -- "/add-comment/new.tsx"


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

&lt;/div&gt;

&lt;p&gt;You could also just organize your project in a way that allows you to have the same two components as child routes to achieve the same thing but then why is “Outlet” useful? It provides a way for you to pass down any UI state to your nested routes. That might be more difficult when your two components are in separate files and the parent component is not using “Outlet”. At least here Remix gives you options based on your needs.&lt;/p&gt;

&lt;center&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%2F2p1hx45sqxixa6oshkmj.png" alt="routing-example-four"&gt;

&lt;p&gt;
&lt;b&gt;
Going back to our admin example, the image above shows what your project structure would look like without using Outlets but trying to achieve the two routes for admin and normal user.
&lt;/b&gt;
&lt;/p&gt;

&lt;/center&gt;

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

URL -- localhost:3000/dashboard
renders -- "index.tsx"


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

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

URL -- localhost:3000/dashboard/admin
renders -- "admin.tsx"


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

&lt;/div&gt;

&lt;p&gt;Overall, nested routes to me were a bit of a challenge to understand at first but slowly I realized how powerful it was and how great it really makes things work out. This is something you don't quite get out of the box with React. Then when combining React with React Router it makes your application that much more powerful. What is great about Remix though since it is from the same creators that built React Router, is that they use that under the hood of Remix too! Neat! Let us look at Actions next!&lt;/p&gt;

&lt;h3&gt;
  
  
  Actions
&lt;/h3&gt;

&lt;p&gt;Actions are how Remix handles form data requests. As the user fills out the form and clicks submit then the action function processes the data. From there you can sanitize and save the input to the DB or anything else you need to do with that data. Remix even provides a way for you to add validation errors for your form inputs! I mentioned earlier about some React functionality in the browser. This is where some of that comes into the picture.&lt;/p&gt;

&lt;center&gt;
&lt;p&gt;
&lt;b&gt;
This image below shows what it might look like within an action function.
&lt;/b&gt;
&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%2Fwuw95xz3temq3kisahde.png" 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%2Fwuw95xz3temq3kisahde.png" alt="actions-example"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;/center&gt;

&lt;p&gt;The action function is auto wired, and Remix will know what to do with that function. When the form is submitted, this function gets executed. Line 12/13 is where we get the form data and, in this case, we grab “userInput” (you will see where “userInput” comes from later, but it is basically something I defined in the HTML output). Lines 15-23 is our error message handling. It is basic error handling currently. I have it checking if the value is null then display the error message "User input is required". In line 16 we define our errors and validations for each input. In line 18 we check to see if there were errors. Then at line 21 if there are any, we return the errors instead. Down at line 29 I return null because I didn't want to redirect anywhere but you could potentially return a redirect and navigate to another screen.&lt;/p&gt;

&lt;center&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%2F8jgbdmah32vjg9h8i4lc.png" 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%2F8jgbdmah32vjg9h8i4lc.png" alt="actions-example-two"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;
In the above image we see the component and what it returns as html to the UI.
&lt;/b&gt;
&lt;/p&gt;
&lt;/center&gt;

&lt;p&gt;To wrap it all together this “New” component that I created renders the form that when submitted triggers our action function above. Line 40 is how we retrieve the errors if there are any then we display those errors in line 60. Line 42 we use transitions which is part of the React functionality in the browser I was referring to earlier. Line 43 follows that up and allows us to tell the UI that something is being processed after submitting the form so we can use that value to disable the button or do anything else we would like to. Notice on line 51 the name of the input, that is how we tie the input from the HTML code to what we are retrieving in the action above.&lt;/p&gt;

&lt;center&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%2F5biewft4tp48geolasyp.png" 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%2F5biewft4tp48geolasyp.png" alt="actions-example-three"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;
This image above contains imports used.
&lt;/b&gt;
&lt;/p&gt;
&lt;/center&gt;

&lt;p&gt;The imports at the top are for React (Form, useActionData, and useTransition). You will also notice the Node ones (json) as well. Remix even provides you with TypeScript typing if you are using Typescript with Remix. There is no restriction however and you can most certainly write in plain JavaScript.&lt;/p&gt;

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

import { Form, useActionData, useTransition } from "@remix-run/react";
import type { ActionFunction } from "@remix-run/node";
import { json } from "@remix-run/node";

type ActionData =
    |   {
            userInput: null | string;
        }
    | undefined;

export const action: ActionFunction = async ({ request }) =&amp;gt; {
    const formData = await request.formData();
    const userInput = formData.get("userInput");

    const errors: ActionData = {
        userInput: userInput ? null : "User input is required"
    };
    const hasErrors = Object.values(errors).some(
        (errorMessage) =&amp;gt; errorMessage
    );
    if (hasErrors) {
        return json&amp;lt;ActionData&amp;gt;(errors);
    }

    // post to API

    // redirect
    // return redirect("/dashboard/add-comment")
    return null;
};

export default function New() {
    const errors = useActionData();

    const transition = useTransition();
    const isCreating = Boolean(transition.submission);

    return (
        &amp;lt;&amp;gt;
            &amp;lt;h2&amp;gt;Form&amp;lt;/h2&amp;gt;
            &amp;lt;Form method="post"&amp;gt;
                &amp;lt;input
                    type="text"
                    name="userInput"
                /&amp;gt;
                &amp;lt;button
                    type="submit"
                    disabled={isCreating}
                &amp;gt;
                    {isCreating ? "Creating..." : "Create New"}
                &amp;lt;/button&amp;gt;
            &amp;lt;/Form&amp;gt;
            {errors?.userInput ? (&amp;lt;span&amp;gt;{errors.userInput}&amp;lt;/span&amp;gt;) : null}
        &amp;lt;/&amp;gt;
    );
}


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

&lt;/div&gt;

&lt;center&gt;
&lt;p&gt;
&lt;b&gt;
The code block above showcase the full file. Not bad right?
&lt;/b&gt;
&lt;/p&gt;
&lt;/center&gt;

&lt;p&gt;That is basically Remix Actions in a nutshell! I really am amazed at how simple it is to just get a form set up. It feels like a very different experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is next?
&lt;/h3&gt;

&lt;p&gt;That was a lot of remixing for now. I think what I have seen so far barely scratches the surface and I hope it helps get you excited about this framework a little bit more to want to explore it deeper. I know I enjoyed exploring what it has to offer and so far, I am liking the developer experience that it provides.&lt;/p&gt;

&lt;p&gt;Some of the things that piqued my interest was one the idea of “Progressive enhancement”. By this they mean that the application you build works without JavaScript in the browser! Sounds crazy but I would like to learn more. From their tutorial they walk you through disabling JavaScript on your browser and you can still interact with the application! It’s quite fascinating but somewhat makes some sense as most of the code is on the server with very little JavaScript on the browser. They say it makes the UI more resilient to network issues. I am still a bit skeptical on that, but I will take their word for it. To me it sounds like your web apps built with Remix will run smoother on mobile without having to download so much JavaScript! Which means users in locations that don't support 4G or even 5G now can load your application faster! If that is what they mean by network issues, then that makes sense!&lt;/p&gt;

&lt;p&gt;Another thing that also interests me is state management. We are all so use to using React state management libraries like Redux that I am curious what we would use here. Although as I write this and think about it, the LAMP stack didn't use state management and it didn't have to cause all the data came from the same server it was in. Your server is essentially the state manager. Maybe that applies here as well? I’m not too sure but I am excited to explore that a bit more.&lt;/p&gt;

&lt;p&gt;There are so many other features it offers that I didn't discuss here such as the capability to give you &lt;a href="https://dev.to/pahanperera/visual-explanation-and-comparison-of-csr-ssr-ssg-and-isr-34ea"&gt;SSR/CSR/SSG&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hopefully by me writing this and you reading it, I have piqued your interest a bit more on Remix! Thank you for reading all the way through. If you have scrolled all the way down here looking for the TLDR well...&lt;/p&gt;

&lt;p&gt;TLDR:&lt;br&gt;
Remix has a great developer experience and is super easy to get into. Their documentation is amazing! If you already know React and are itching to learn something new why not dive in?&lt;/p&gt;

&lt;p&gt;Cover image credit: &lt;a href="https://unsplash.com/photos/T3Neg57nlYs" rel="noopener noreferrer"&gt;https://unsplash.com/photos/T3Neg57nlYs&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>remix</category>
      <category>react</category>
    </item>
    <item>
      <title>How 'git reset' isn't as scary as it looks.</title>
      <dc:creator>Raymond Luu</dc:creator>
      <pubDate>Tue, 26 Jul 2022 15:32:31 +0000</pubDate>
      <link>https://dev.to/devsatasurion/how-git-reset-isnt-as-scary-as-it-looks-e0g</link>
      <guid>https://dev.to/devsatasurion/how-git-reset-isnt-as-scary-as-it-looks-e0g</guid>
      <description>&lt;p&gt;For me &lt;code&gt;git reset&lt;/code&gt; did look scary initially when I was first learning Git. But now that I have a better understanding after using the command more often and looking at the git history to understand what happened. At first glance this could be very daunting but it gets less daunting after you get a bit more comfortable with what is going on.&lt;/p&gt;

&lt;p&gt;Before we get started, I want to mention my blog post is intended to help get you get comfortable with the &lt;code&gt;git reset&lt;/code&gt; command if you are a beginner with using Git. If you are already a seasoned Git user, then I would still appreciate your input and thoughts. Join the conversation and teach me something I don't know about reset! I challenge you to do so! Let's get started!&lt;/p&gt;

&lt;p&gt;Here are a few things you should understand before diving in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Committed versus Uncommitted code&lt;/li&gt;
&lt;li&gt;Staged versus Unstaged code&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  So what is the reset command?
&lt;/h3&gt;

&lt;p&gt;It is essentially your undo button in the Git world. Your CMD+Z for MacOS. Your Ctrl+Z for Windows. Etc. Granted though, in Git you could always just undo your code changes and then create a new commit over the latest commit. You are basically doing the same thing but you have to take an extra step in changing the code manually. Doing it manually is easy when there are only a few lines of code but when you are dealing with 100+ lines that have been changed, you can save time with using &lt;code&gt;git reset&lt;/code&gt;. (Plus you will feel amazing running this command) Now why should we use &lt;code&gt;git reset&lt;/code&gt;?&lt;/p&gt;

&lt;h4&gt;
  
  
  Here are two reasons why we would even care about 'reset':
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;When you have committed lots of WIP (Work in progress) work that needs to be cleaned up from your commit history on your local feature branch&lt;/li&gt;
&lt;li&gt;When you have made a mistake somewhere in code (50+ lines of breaking changes) and you really need to hit the undo button quick (trust me happens to the best of us we are all human after all)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you are executing the 'reset' command you are modifying commit history. What happens is the commit(s) that you reset will be gone. This means that 'git reset' puts the changes back into staging/unstaging. The previous commit(s) are removed and you are now free to move changes you want to keep into a new commit and throw out changes you don't want.&lt;/p&gt;

&lt;p&gt;This is a great tool if you are working individually on your own branch but &lt;code&gt;git reset&lt;/code&gt; will have huge impacts on your feature branch if you are working with another dev on the same one. This is because you are modifying existing history and removing that history from existence. &lt;/p&gt;

&lt;h4&gt;
  
  
  Example on why this can be dangerous
&lt;/h4&gt;

&lt;p&gt;Say for example, another dev has pulled your changes down to help you with the feature/fix before the reset. You then find some code changes that you want to reset. You then run the 'git reset' command to undo those changes. The result is your local vs remote branch HEAD commits differ. Git will tell you that you need to force push your changes when you try to push these changes to the remote branch. You then proceed to do that and the results there now are that the remote branch has your 'undo' changes while your dev partner has the old changes. If he tries to 'git pull' your branch it will cause errors when merging due to the fact that the HEAD commits between the remote branch and his are different. They have commits in their branch which are non-existent anymore. This causes headaches and requires the other dev to completely delete their branch and pull your branch down again.&lt;/p&gt;

&lt;h4&gt;
  
  
  Here is an example showing some Git history before and after a &lt;code&gt;git reset&lt;/code&gt; command is executed.
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VMeV9U_w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4qv9cgtkaxaqbd791bwb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VMeV9U_w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4qv9cgtkaxaqbd791bwb.png" alt="before-reset" width="458" height="183"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In the image above, I created a repository with two commits just adding 2 files to the project (file a and b)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--umzR44-S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l8knop5fs5mlkdhge4e1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--umzR44-S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l8knop5fs5mlkdhge4e1.png" alt="reset-done" width="494" height="35"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The command above shows that I chose to reset to the hash starting with 'bf59e' meaning I want to undo the changes which were made in commit hash '7d313'. If there happens to be another commit after 'bf59e' (say 'abcede') and I had decided to reset to that one instead, I would have ended up undoing the changes in both '7d313' and 'bf59e'. 'git reset' will basically reset everything between the HEAD (your current latest commit) to the one which was chosen.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oZTfZcod--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uigg5c02xs0oa5ph5kcs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oZTfZcod--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uigg5c02xs0oa5ph5kcs.png" alt="after-reset" width="450" height="103"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This image above is the result of the reset done in the previous image.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4MODRv_W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gdpsbhk4vtpqbtd73pu2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4MODRv_W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gdpsbhk4vtpqbtd73pu2.png" alt="reset-take-action" width="550" height="122"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This image above shows the changes that have been reset. The original commit added the file. Now the file is back in my untracked unstaged changes and is ready to be modified for recommitting. You can then add back in the changes you want to go through and leave out the unwanted changes. My example only has one change but imagine having 20+ changes which you are trying to reset. Modifying the changes manually can take a lot of time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  What about 'git revert'?
&lt;/h3&gt;

&lt;p&gt;A similar command is 'git revert'. This is the safer of the two commands you can do if you are unsure but are trying to undo some of the changes you made. No matter where you are in your codebase this command will create a new commit on top of your existing ones with the undo changes. Whether you are in your main/dev branch or your feature branch you will always see a new commit after this command is executed with a message indicating there was a "Revert". All you need to provide is the commit hash that you want to revert. This command is safe to be used in any branch whether you are the only one working on it or your team is also working on that same branch together. The 'git revert' command has no impact on anyone working on the branch as a new commit is created on top of the existing ones. The commit history goes forward rather than backwards. (not removing any git commit history while still undoing code changes)&lt;/p&gt;

&lt;h4&gt;
  
  
  A reason to be using revert would be:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;When you have released a feature too early and need to rollback (the feature has already been merged in with the rest of your codebase main/dev branch)&lt;/li&gt;
&lt;li&gt;The same reasons mentioned with using 'git reset' could also be applied here.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Here is an example showing some Git history before and after a 'revert' command is executed.
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vPxI0e3s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xoso5e3ydj688rrpb9an.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vPxI0e3s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xoso5e3ydj688rrpb9an.png" alt="before-revert" width="458" height="183"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The above image is showing the same repository as in the 'reset' example.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Gi1akOkv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1do3nwavxcanegwt4k3s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Gi1akOkv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1do3nwavxcanegwt4k3s.png" alt="revert-message" width="505" height="164"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This image above shows the message that you see after running the command to revert.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jPiT7E-r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f37vlwngogp5jdhl1rv6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jPiT7E-r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f37vlwngogp5jdhl1rv6.png" alt="revert-done" width="497" height="72"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In the image above the revert is complete. Notice I chose to revert commit '7d313'. With 'revert' we choose the commit hash that we want to undo (different from reset). In the end we are still undoing the same changes but we select a different commit hash when we execute the command.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YfbiHuCE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l46ecgbvg5f66stpr2x9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YfbiHuCE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l46ecgbvg5f66stpr2x9.png" alt="after-revert" width="472" height="297"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;From the image above we got the results and we see an extra brand new commit. The message for the commit indicates that a 'revert' has happened with the commit hash which was selected.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;In conclusion, 'git revert' is undo with history and 'git reset' is undo without history. Both are very great tools to use when trying to undo mistakes we have made. This just scratches the surface of these two commands there are still more complex things you can do with them. There are many options you can add to them that will enhance what they do. Those I am still exploring and if you are interested in reading more let me know!&lt;/p&gt;

&lt;p&gt;TLDR: 'git revert' moves you forward in git history; 'git reset' moves you back in git history. They are both great useful tools for undo-ing any mistakes.&lt;/p&gt;

&lt;p&gt;Thanks for reading! Have a great day!&lt;/p&gt;

&lt;p&gt;Cover image credit: &lt;a href="https://unsplash.com/photos/TgQUt4fz9s8"&gt;https://unsplash.com/photos/TgQUt4fz9s8&lt;/a&gt;&lt;/p&gt;

</description>
      <category>git</category>
    </item>
  </channel>
</rss>
