Latest Tutorials

Learn about the latest technologies from fellow newline community members!

  • React
  • Angular
  • Vue
  • Svelte
  • NextJS
  • Redux
  • Apollo
  • Storybook
  • D3
  • Testing Library
  • JavaScript
  • TypeScript
  • Node.js
  • Deno
  • Rust
  • Python
  • GraphQL
  • React
  • Angular
  • Vue
  • Svelte
  • NextJS
  • Redux
  • Apollo
  • Storybook
  • D3
  • Testing Library
  • JavaScript
  • TypeScript
  • Node.js
  • Deno
  • Rust
  • Python
  • GraphQL

Getting Started with PrimeNg: 3 Most Useful Components for Your Angular Project

In this article, we'll learn how to use PrimeNG in your angular project from scratch. Since PrimeNG is a massive collection of UI components, we've picked the three most useful ones which any beginner can use in their angular projects. We'll be implementing autocompletion, chart model, and form validation features in this article.PrimeNG is an  open-source  library consisting of various UI components for angular. It is developed by a firm called  PrimeTek Informatics.  What makes angular one of the most sought after frontend development framework is, it's component-based design. In traditional web applications, the entire page was reloaded with the requested page. But, with the use of angular, we have something called  SPA s (Single Page Applications) wherein, the current page is dynamically rewritten with the new data. That is to say that, a particular component is reloaded with the latest data. So, we can conclude here that angular applications are  component extensive . This makes it paramount to design reusable, scalable, and lightweight components. This is where UI component libraries come to picture. They make it easy to use and implement components along with appealing UI for our angular projects. Also, allows you to focus more on the business logic than the UI design, thereby increasing your productivity. In this article, we'll discuss one such library,  primeNG , as the title suggests. There are other such libraries like  Angular Material ,  NGX Bootstrap , etc. We'll list a few features of primeNG Learning or implementing primeNG would require the minimum knowledge base in Angular as a prerequisite. Because primeNG is a UI component library, one should know the usage of components in an angular project. I'd also like you to go through the following checklist of the technology stack we'll use. Let's get started by creating an angular project. Fire the following command in your command prompt to create an angular project by name angular-primeng-tutorial . Before we jump into the implementation, we'll install primeNG, which is available in npm. Run the following commands to install primeNG and prime icons, which is a font icon library from the same vendor. And we'll also install angular animations for enhanced user experience. You can run these commands in either command prompt or your VS code terminal. Add the following dependencies in your index.html file. Add the following dependencies in your styles section of the angular.json file. We have added these dependencies for our primeNG module to work fine. Once installed, the components can be made available by importing from primeng/*. Autocompletion is nothing but, suggestions given on typing. Suppose it's a country field and you start to type 'x', the application suggests you countries starting with x. Let's import the ' AutoCompleteModule ' from primeng into our app.module.ts file. This is how my file looks like; Let's go ahead and paste the below code in our app.component.ts file. What we're doing here is we're creating an array string called 'bookGenre' with some data and a function called 'search' triggered by an input event. The function filters your data dropdown list based on the first letter of the user's input. This is how our app.component.html looks. You can see that we've used the autocomplete tag here. It has these attributes: You can further make the [dropdown]="true" as [dropdown]="false" if you don't want a dropdown. Also if you want to make multiple selections, then add [multiple]="true" . The three different types of autocomplete we discussed will look like this: Angular is all about the frontend part of a web application. And most of them deal with the display of information for its users. Not many of us are interested in a long slogging bulletin of information. Instead, short, precise, and pictorial ones are preferred. Charts are one such way to summarise years of data and give subtle insight into what we intend to convey. Charts can be both informative and visually appealing. It is straightforward to use different kinds of charts in primeNG. Here, we'll learn the bar chart and see it's different possible options. First of all, we need to install the npm package by the below command. Mention the same in the scripts section of the angular.json file. Import the module for it to be available for use in the code in your app.module.ts file. Now, in your  .html  file, type the below code. The tag p-chart signifies the primeNG/chart module tag. And in the type option, we can mention the kind of chart we want to use,  bar ,  pie ,  line , etc. Data is bound and rendered from the ts file. Type the following code in your corresponding  .ts  file.  Data  has  labels  and  datasets  in the form of JSON bodies, as seen below. Labels indicate the name of the data you want to compare with. The different data are available in the form of  datasets . We can specify the color, width, and other styling options here other than data. We can improvise this further by adding options . With the use of the below code, we can give a title to our chart and mention the position of the chart legend. In .html and .ts files respectively. We can also bind events to the chart elements. This is how we do it: Here, the event trigger is, onDataSelect . When you select any data in the chart, it displays the respective value of it. Paste the below codes in .html and .ts files respectively. This is what our final result looks like! Forms are used in almost every web application, contact us, survey forms, feedback forms, etc. Implementing them using primeNG is more comfortable and comes with a lot of customization and validation options. In this demo, we'll design simple user details form using primeNG. Update the  app.module.ts  file with the following import statements. We need these modules in our form to function properly. Don't forget to add them to your imports as well. Now, for our user form, we'll consider the first name, last name, password, and description as our input fields. The .html file looks like this. The p-panel tag forms the header part of the form. We ave used the [formGroup] from angular/forms module. We have used the required attribute for mandatory fields. To display messages we have used p-message tag. Also notice that the validations are checked by . valid and . dirty properties. For the password field, we have an additional length validator using [minlength] property. Lastly, the submit button is disabled until the entire form passes all the validations. This is what our .ts file looks like. Here we're making use of the angular form validators, along with required and minlength properties. We're making use of messageService module to display messages. Check the picture below to see the final result! This is how the form validations using primeNG looks like. I hope the article was useful for you! In this article, we learned about the features and usage of primeNG. We implemented three of its most useful components. Without the use of primeNG too, these features can be achieved. But, it's an uphill task when compared to the ease of primeNG. You just have to install the npm package and import the modules you want you to use, and you're good to go! There are a lot of other UI components you can check out and try yourselves. PrimeNG documentation: https://primefaces.org/primeng/showcase/#/ Tutorials: Tutorial Sample 1 , Tutorial Sample 2 .

Thumbnail Image of Tutorial Getting Started with PrimeNg: 3 Most Useful Components for Your Angular Project

How to build a React drag-and-drop component for file upload

In this article, we’ll build a simple React application for dragging and dropping files. We'll make use of the HTML5 drag-and-drop API and we’ll discuss the useReducer hook for managing state. React comes with a multitude of component libraries that you can use out of the box, but the more dependencies you add to your project, the more likely you are to end up with broken code as time goes by. Thus, even if it takes a bit longer, it's always preferable to write your own, non-bloated components, instead of adding dependencies for the smallest tasks. In this article, we'll learn how to create our own drag-and-drop component in React, and we'll use the HTML5 native DnD API for this. By the end of this tutorial, you should have a good understanding of how the HTML5 drag-and-drop API works and how to build your own DnD component in React.  To be able to follow along, you should be familiar with how React hooks and APIs work. If you’re just starting to learn React, it might be better to first check the articles below: In this tutorial, we'll create a simple React app that allows us to drag and drop files, and lists the file name and thumbnail in the drop area. The code for the final app is here . And here's how it looks: Before we dive into the React code, we'll discuss the basics of the HTML5 drag-and-drop API, as well as the React useReducer hook. I’ll start by explaining how the DnD API works in HTML5.  In the earlier versions of HTML, creating this behavior required using JS or a framework like jQuery, for faster coding. However, in HTML5, this behavior is native, so you no longer have to find a workaround. All major browsers support DnD, as you can see here . The principle behind this behavior is very simple: an element will take on the draggable role, and another element will become the drop target or drop zone .  So in any drag-and-drop application, you will have these two parts: the element that can be dragged, and the area where it can be dropped.  HTML5 allows any element to become draggable by simply adding this attribute and setting it to “true”:  This is how you tell your app that you want to be able to drag a specific DOM element. However, making an element draggable isn’t enough; in order to enable the actual behavior, you also need to attach event listeners that tell the app what functions to execute when the element is dragged or dropped.  For  the draggable element, the available events include:  On the other hand, for the drop area, you can use the following events:  How do these work together, in practice?  First, you make an element draggable. Then, you attach the suitable event listeners to the draggable element. For example:  At this point, if you start dragging the element, the drag(event) function will be called. Here’s how this function could look:  In this function, the dataTransfer property holds the event’s data and comes with specific methods for managing the dragged data. The method used above, setData() , is used for adding an item to the dragged data.  You can use different types of data here, such as:  The value of the dragged data is defined by the event.target.id .  Once you drag an element, you want to be able to drop it as well, so you need an area where you can drop it. To define a drop zone, you have to use the ondragover event.  Here’s how this looks:  By default, elements can’t be dropped in other elements, so if we want to drop a paragraph in a div, we need to cancel the default behavior of the div. This means that the function called by the ondragover event listener will prevent the default behavior, like this:  Finally, the ondrop listener above calls the drop(event) function, which looks like this: Just like before, we're preventing the default behavior and mentioning the data type that can be dropped in the drop area. Then, we're telling the app that we want the dragged element to be appended to the drop area, once dropped. This is it, here's a simple example of a drag-and-drop HTML5 application: Now let's quickly talk about the useReducer hook in React. This hook is an alternative to the useState hook, and is generally used in applications with complex state. It takes a reducer function and an initial state as input, and returns the current state and a dispatch function as output. Here's how this looks in practice: A reducer function takes two values and returns a single one, as shown below: In this case, the initialState would be: So we have an app where the initial count is 0, and we have a reducer that applies an action to this state, to increment or decrement it by 1. This happens when a counter button is pressed. Here's how this component could look: The full code looks like this, and you can find it here : The useReducer hook "applies" the reducer function to the initialState object, so this means that whatever the value of the state was, it will be incremented or decremented by 1. The case inside the reducer tells the app which function to call and apply when the button is clicked. So to come back to this line: The dispatcher dispatches an action that updates the state. The action is the one defined by useReducer . Here's what our counter looks like: Now that you know what the useReducer hook does, and how the HTML5 DnD API works, let's put these together and build our file drag-and-drop app. We’re ready to build the React drag-and-drop component. To make this easier to digest, I’ll split the tutorial into three parts:  I’ll be using codesandbox.io for this tutorial, and you can find the final code here .  I have no other dependencies installed, so my project structure looks as follows: We’ll start by editing the App.js file.  Now, we'll create the <DragAndDrop/> component, in the same file: In the styles.scss file, add the following code: Here's what we have until now: Of course, nothing actually happens at the moment, as there is no draggable file yet. Also, we haven't added any event handler, so the App doesn't know how to handle a file if we try to drop it in the <div className={"drag-drop-zone"}> . So let's start by adding the event handlers mentioned at the beginning of this article. We'll need to tell the app what we want to drag and where we want to drop it. We're going to use event listeners similar to the ones mentioned in the first part, except that in React they're written in camelCase. So in your App.js file, add the following code: For now, we're just preventing the browser from opening the files. We want our events to do the following: We'll define these actions inside a reducer function, but before doing so, let's declare the initial state of our application. In the App.js file , under the App() function, add the following above the return statement: So initially, our file list is empty and our draggable files are not in the drop area. Now let's define the reducer. In the App.js file, under state but before the return statement, add this code: What's happening here? The reducer takes the initial state and returns a new state, by applying one of the actions mentioned inside the switch statement. So if we dispatch the AddToDropZone case, this action will be used on our file. Then, the useReducer hook takes the reducer function and applies it to the state . Basically, whatever we pass to the dispatcher function when calling it in the app will take the action defined in the reducer. Now we need to update our event handlers, to make use of the newly defined functions. We'll start with handleDragEnter : Then, the updated handleDragOver constant: Here we've added an effect to the dataTransfer() method. The "copy" operation indicates that the data or file being dragged will be copied from its current location - which is your PC - to the drop zone. Finally, the updated handleDrop constant: This handler checks whether there is any file in the drag operation and if there is, it triggers the two actions - AddToList and AddToDropZone. So our files will be dropped in the drop area, and their names will be added to a list under the zone. So our App.js file now looks like this: Notice that in the return statement of the App() function, we're passing the data and dispatch as props to the DragAndDrop component: Under the drop area, we're listing the dropped files. We use the .map() method to create a new list item whenever a new file is dropped. We're almost done, but right now we're just listing our dragged files under the DnD container. Let's adjust the app so that we actually see them inside the <DragAndDrop /> component: Here's what we've changed: Now we're ready, here's our final React DnD component: I hope you enjoyed this tutorial! Now you know how to build your own DnD component in React, but if you prefer to use ready-made libraries, you can try some of the options below:  

Thumbnail Image of Tutorial How to build a React drag-and-drop component for file upload

I got a job offer, thanks in a big part to your teaching. They sent a test as part of the interview process, and this was a huge help to implement my own Node server.

This has been a really good investment!

Advance your career with newline Pro.

Only $30 per month for unlimited access to over 60+ books, guides and courses!

Learn More

The Rust Map Function - A Gateway to Iterators

This post looks at the Map function in the Rust programming language as one of the basic tools to use and interact with collections and iterators.Arguably one of the main reasons the Rust language has become so popular is because the entire ecosystem builds upon a consistent experience. From toolchains to documentation and language specifications, almost every aspect of the language adheres to a certain level of consistency. Getting into the Rust mindset allows us, developers, to intuitively discover aspects of the language and gain the ability to write better and more consistent code. In this article, we are going to focus on Iterators - one of the key language tools enabling us to write idiomatic Rust code. This may surprise you at first, especially if you are coming from other programming languages (for example Swift or JavaScript), where working with types like lists and arrays does not immediately expose the concept of Iterators. The opposite is valid for Rust. Iterators cover a very large number of applications and as such, being comfortable with their use greatly facilitates becoming a better Rust developer. In order to follow along, you will need at least some familiarity with the Rust programming language. To make things easier, this article includes detailed code samples and links to the Rust playground where you can execute and study the provided code snippets. After reading this article, you will know: A core concept for Functional programming, Map is also commonly used as a tool for dealing with lists and collections in Rust and is one of the most essential methods for working with Iterators. The map method offers a way to apply a function (or a closure) on each element from a list. This is key in functional programming methodologies and offers a way to transform a collection of type A, to a collection of elements of type B. In Rust, the map method is frequently used to interact with vectors and any other types which can be represented as an Iterator . Let's illustrate this with an example. Imagine a list of numbers (a vector of numbers) and we would like to multiply each number by 10. Try it out for yourself. Let's review a breakdown of the steps You may be wondering why .map() doesn't work directly on the vector of numbers. The answer lies with the fact Rust makes it very easy to use iterators for almost everything. In the ergonomics of the language, it is generally preferred to use iterators instead of directly interacting with a vector. In the example above we actually have two iterators at play - the first which we obtain through the use of .iter() in order to get the elements of the vector and a second one which happens to be the return type of the .map() function! This may be a bit surprising at first, especially if you have a background in other programming languages (for example Swift or JavaScript) but indeed, in Rust .map() also returns an iterator. Let's have a closer look at the syntax we need in order to use Map. In the Rust documentation , we can find the exact signature of the Map method: With this we can focus on several key takeaways. .map() can only be applied to iterators. This means that we first need to convert a collection type to an iterator before we can transform its elements. To obtain an iterator from a vector, the standard library provides .iter() and .into_inter() . The return type of .map() is also an iterator. This can be very useful in cases when multiple transformations need to be chained one after the other. Let's illustrate this by extending the example with a second transformation of the vector of numbers. After multiplying by 10, let's divide each element by 3: Try it out for yourself. Since the Map function returns an Iterator, the result of the first transformation .map(|n| n * 10) will be used as input for the second transformation .map(|n| n / 3) . You probably notice by now that despite the return type of Map being Iterator, we somehow manage to get back a vector of results. This is possible thanks to the .collect() method. It acts as a consumer to the iterator, acquiring all elements and storing them into a vector. The Map function is lazy , meaning the execution of the closure provided to Map is delayed until the values produced by the Map iterator are actually requested. To demonstrate this, let's modify the example so that we count the number of times the closure of the map method is invoked: Every time .map() runs, it first increments the counter and then applies the transformation of multiplying the number by 10, similar to what we did in the previous example. As expected, the counter equals 4 because this is the total number of elements on which the map function was applied. Now let's modify this snippet by not calling .collect() at the end: Try it out for yourself. If we print the contents of the result variable, we see that what we get back is the actual Map iterator, the results of which are not materialized yet. We can prove this further by looking at the value of the counter variable which is now 0. This means the function inside the .map() has not been executed yet. The lazy nature of .map() gives us the opportunity to control when the transformation will be executed. You can imagine this can be significant in cases of large data sets where performance is important. Let's have a look at several examples in which the Map function can be a good solution. Try it out yourself. Starting from a vector of string values (or "words"), we can use the Map function in order to get the lowercased equivalent of each word. As before, we begin by accessing an iterator over the collection words. The .iter() method produces an iterator which yields every element (that is, every word) of the collection. Then we can use Map to define a closure which applies to_lowercase() on each element. In the end, we don't forget to .collect() the results into a new vector of String values. Let's define a string value and use Map in order to determine the number of occurrences of each character within the string. We expect an output giving the number of times each character is used, similar to the following: The result looks like a dictionary where every key is a character and the value of that key is the number of occurrences. Let's use the HashMap type to represent this value: Try it out for yourself. Here we use the chars method in order to obtain an iterator over every letter of the alphabet. Then we count how many times each letter matches the text input. For example, how many times "a" appears in "hello from rust!", then how many times "b" appears in "hello from rust!" etc. Finally, we collect the results from the mapping into a HashMap. So far we've used examples where the mapping function always succeeds. In reality, we have to take into account the circumstances when this is not going to be the case. Such cases include transformations that have an optional return type like Option or Result . Let's illustrate the case of using Map with an operation that can potentially fail. For example, converting a vector of string values to a vector of numeric values of type u32 . Applying what we've seen so far, we may attempt to solve the problem with the following snippet: Try it out for yourself. For each element of the vector, we use the parse method in order to convert the string value to a number. We realize quickly that this will not compile. The reason lies with the fact that Parse returns a Result<u32, std::num::ParseIntError> which indicates that the operation can either succeed returning a value of type u32 or fail with a ParseIntError . The map function is not equipped to deal with this situation directly. One way to solve the problem is to use .unwrap() , essentially forcing the fact that we are certain the parsing will never fail. If it does, the program will panic and exit: Try it out for yourself. This works because all string values in the source vector can be converted to a number. But what if we have a vector where some elements can't be expressed as a number? The unwrap fails and causes the program to panic. Luckily, the standard library provides an alternative that can handle the situation where the Map function can produce one or zero results. Meet flat_map() : Try it out for yourself! flat_map uses an iterator over the result of the mapping and as a consequence, it will skip over elements for which the mapping closure returns empty or unsuccessful values (like None or Err . In other words, we have a mechanism to skip over the failing elements and end up with a resulting vector of numbers for which the operation succeeded. A note of caution regarding side effects when using the Map function. Side effects refer to the fact that during the execution of a Map closure or a function, our program may modify state and variables which are external. We already saw an example of this, when we defined a counter which increments every time the Map function is executed: While this produces exactly the result we expect in this situation, it may not always be the case. Let's modify the example so that instead of transforming the numbers in the vector, we map the order in which they are processed: Try it out for yourself. This results in the Map function to first be applied to the number 3 on position 1, followed by the number 6 on position 2, etc. Since .map() returns an iterator, we could choose to modify its output. For example, let's reverse the order of the Map operation: Try it out for yourself. So the first number to be mapped was 12, followed by the number 9. The order in which the elements were mapped is no longer the same as the initial order in the vector. In order to ensure we have better control of operations with side effects, it may be preferred to use a for loop instead: Try it out for yourself. After seeing the Map function in action, we can outline several important takeaways. You may also find it useful to explore the Map function specification in the documentation which reveals all available methods and additional sample use cases and code snippets. When I need more information regarding an aspect of Rust, I find myself browsing the Rust Programming Language Book . I think it's an amazing resource for gaining further insight into concepts regarding Iterators, the Map method, or working with vectors. If you are curious about Iterators, you may want to further explore other helpful methods like .filter() and .fold() .

    How to install Node.js and npm on macOS

    In this post, we'll be looking at three different ways to install Node.js and its package manager, Node Package Manager, on macOS. We will discuss how to install Node.js using mac-native package installer, homebrew, a 3rd party installer, Node Version Manager and how to hop between different Node.js versions using Node Version ManagerNode.js is an open-source runtime environment, which allows developers to create networked applications and web-servers in JavaScript. The main thing to remember is that Node.js is asynchronous and event-driven , which means it can support hundreds of simultaneous calls in the event loop. Basically, this means that a Node-based server does not wait for an API to return data. You can see a great example of asynchronous programming in Node.js here. Node.js therefore shines in building fast, data-intensive, and real-time network applications, such as Uber and PayPal. However, you can also use Node.js to build your private blockchain. When using Node.js, you’ll also need to use Node Package Manager, or npm for short. npm is a package management framework for Node.js. It provides a command line utility tool to install Node.js libraries and manage their versions and dependencies. If you’ve ever used other programming languages, such as Ruby or Python, then you’ll notice that npm is analogous to rubygems in Ruby or pip / poetry in Python. In this post, we'll learn how to install Node.js and Node Package Manager (NPM) in a macOS environment. This post is intended for complete beginners to JavaScript or for folks switching from Ruby or Python to JavaScript for their backend production. It doesn’t assume any background knowledge of JavaScript (although it doesn’t hurt to have some!). However, this tutorial will cover everything you need to know and hopefully will get you up to speed in no time! Ready? Let’s jump in. To check whether you already have Node installed, open new terminal window and type: If you have Node.js installed, it should output Node’s version. If you don’t, you’ll see one of the two messages, depending on whether you use bash or zsh shell: - bash: command not found: node - zsh: command not found: node That means that the command you are trying to run is not installed. But worry not, there are several ways to install Node.js and NPM: I’ll go over each method step-by-step. Visit the Node.js website where you can download a pre-built installer for your mac platform. There are two types of Node.js releases: long-term support (LTS) and current . LTS releases are more polished and bug-free and will suffice for the majority of everyday users. Current releases are typically more experimental and contain the latest features, which may not be completely finished and could occasionally crash. You can switch between LTS and current versions by highlighting the field in the first tab. Again, the LTS version is recommended for most users. Therefore, if the LTS tab is highlighted in dark green, you can simply click on the macOS Installer option, which will download the .pkg installer for Node.js. This installer will also automatically install NPM for you. Just follow these steps: You should now see output v12.18.0 or some other version of the software that's just been installed. You should now see output 6.14.5 which represents the NPM version. Homebrew is arguably the most popular package manager for macOS and makes installing Node.js straightforward. Let's check whether you have Homebrew installed: If Homebrew is installed on your mac, you should see its version, for example, Homebrew 2.3.0 . If not, you can install Homebrew with the following command: Assuming that Homebrew is already installed, type: And that’s all you need. Again, try node -v to confirm Node.js version and npm -v to confirm NPM version. While using Homebrew for Node.js installation is very easy, it comes with one disadvantage: This could be a problem because sometimes applications require a certain version of Node.js to work. Having the flexibility of using specific versions can be an asset. To fix this problem, the best option to install Node.js is via nvm , which stands for Node Version Manager. Node Version Manager , nvm , is a bash script to manage multiple active Node.js versions. It is easy to run with the following steps: Congratulations, you have now successfully installed and understood the ins and outs of Node.js and NPM. I’ve helped you to explore some very basic commands, but please don’t stop here. It’s just the beginning and it’s up to you where this journey will take you!

    Thumbnail Image of Tutorial How to install Node.js and npm on macOS

      React Router Basics & Redirect Made Easy

      In this post, we will discuss what React Router is and then with the fundamentals in place we will dive into how to handle redirect.Handling routing in web applications has always been a massive challenge. When I used to think of routing, I flash back to my days of using jquery and hiding/showing content depending on the current state of the application. This was painful, led to some crazy bugs and also messy code. Thankfully, we have evolved since then and we have much better ways of managing both state and routing in our applications. We will delve into routing in this post, especially how to handle redirects i.e. when a user goes to a certain URL, we instead send them to another. By the end of this post, you will be able to: Ok, that may seem like quite a lot and you may be a little overwhelmed but we will take it piece and piece, it will all come together in the end. To get the most out of this article, we assume you're familiar with component basics in React, React Hooks, and also core JavaScript. If you do not know any of the above but would like to learn, here are some great resources: Now it's time to get started on our journey of learning React. The first step in using react-router is to install it. As usual, this can be done with npm or yarn . Since we are building a web application we will use react-router-dom which you will use in 99.9% of use cases. Here is a conversation discussing the difference between react-router and react-router-dom . I will be using the terms react-router and react-router-dom interchangeably. So to install, you can run either of the following commands: We can start using the core components of react-router-dom now. When you are setting up basic routing, there are four core components you will use which are: To demonstrate the use of the above components, imagine we have two routes in our application: When our user visits the /hello route, we will render a Hello component and similarly when the user visits the /goodbye route we will render the Goodbye component. We will keep the Hello and Goodbye components extremely simple so we can focus on the routing aspect. So in our base component which in our example is the App component, we can set up our routing. We will first use the BrowserRouter component and the Link component. So the BrowserRouter component acts as a wrapper, then we have our standard HTML elements to create our navigation with an unordered list. Instead of a tags, we are using our Link component. The Link component has a to prop which is similar to href , basically where should we go when the link is clicked. In the above example when Hello is clicked, it will direct you to /hello whereas Goodbye will direct you to /goodbye So not too bad, right? The react router team has done a great job of making it as easy as possible to get up and running quickly with react router. Now to complete our example we will use the Switch and Route component. So let's first delve into exactly what the Switch component is doing. Essentially all the Switch component is doing is looking through each of the Route component(s) and rendering the first one that matches the current URL. The first default path for a website is / , so in our example, we will be rendering just a blank screen at the start (apart from our navigation). The Route component has a path prop which tells our app - Hey, when our URL matches this path then render my children . So when the URL is /hello then we render the Hello component. Isn't this just so intuitive? Using the URL to decide what to render on the page! That is the first basic example covered, you can do so much with just this knowledge! Here is the complete Codesandbox so you can play around with it. Before we head into our redirect example, I first want to go through nested routing as it is quite important to know when setting up routing in your application. We will use the same example as above but we will add an additional link called Tasks which will list some tasks we have, well tasks I have. Our navigation will now look like this: What we want to happen is when tasks is clicked that we present a list of tasks, which are also clickable. Thankfully, this is very similar to the above. When creating our tasks component we are going to use useRouteMatch , this hook will attempt to match the current URL. We use useRouteMatch like so: We can then use this match variable in the to prop of our Link component. In the above case, task is the current task in the loop, which is clear in the below code (our entire Tasks component) So like above we use the Switch and Route component to handle our routing. For our default route we just render: The last thing we need to do is to create our Task component. This will use the useParams hook which gives us access to the selected taskId . Great, we have now got nested routing in our application. Not too bad, eh? Here is the complete Codesandbox . This is the final part we are going to cover which will be much easier as we have covered all the basics above. Handling redirects in a web application is very common, if a user tries to go to your dashboard screen but they are not logged in then you want to redirect them to the login screen. Similarly, if a user is already logged in and they attempt to go to the login page then we will redirect them to the dashboard screen. To accomplish this, we will be using a new component from react-router and that is the Redirect component. You can use the Redirect component to simply redirect a user to a different part of the application. So in our example, we have some basic state in our root component so we can manage the user's logged-in status. We have a couple of routes set up, one is for our dashboard and the other is our default route which presents the login page. So we pass our state into both of our components, we can then handle the redirect in our Dashboard component. So handling the redirect isn't as challenging as it may seem, we simply have ternary in place and if our user is not logged in then we render our Redirect component: We can do something similar in our LoginPage component, if the user is already logged in then we redirect them to the /dashboard URL. That is how you handle redirects, there are certainly more complicated areas you may have to handle but they will be all based on this logic. As always here is the complete Codesandbox . Today we learned: If you're interested in learning further, I really recommend checking out the documentation as it is simply fantastic. Have a great day.