Ashley Parker - Big Nerd Ranch https://bignerdranch.com/blog/category/authors/ashley-parker/ Tue, 02 May 2023 21:08:12 +0000 en-US hourly 1 https://wordpress.org/?v=6.5.5 Now Available React Programming: The Big Nerd Ranch Guide https://bignerdranch.com/blog/react-programming-the-big-nerd-ranch-guide/ https://bignerdranch.com/blog/react-programming-the-big-nerd-ranch-guide/#respond Tue, 02 May 2023 21:07:22 +0000 https://bignerdranch.com/?p=9711 Based on our React Essentials course, this book uses hands-on examples to guide you step by step through building a starter app and a complete, production-ready app, both crafted to help you quickly leverage React’s remarkable power.  Your production-ready app will include a cart, a login page, and other e-commerce features.  What do you need to […]

The post Now Available React Programming: The Big Nerd Ranch Guide appeared first on Big Nerd Ranch.

]]>
Based on our React Essentials course, this book uses hands-on examples to guide you step by step through building a starter app and a complete, production-ready app, both crafted to help you quickly leverage React’s remarkable power. 

Your production-ready app will include a cart, a login page, and other e-commerce features. 

What do you need to know? 

Before you dive into the book, you will want to be familiar with the basics of HTML and CSS. It will also help to have a foundational knowledge of JavaScript, although we will cover some JavaScript concepts throughout the book. You will use these three languages as you build your React application. No need to know anything about React as we will take you through it step by step. 

What will you learn? 

Components 

You will build your application with functional components and JSX. Using components will allow you to reuse code across your application. Components also help organize your code in a logical way that makes it easier to understand and allows for the separation of concerns. 

Hooks 

You will learn how and when to use the most common React hooks: useEffect,  useState,  useReducer,  useRef, useContext,  useMemo,  and useCallback. You will have opportunities to compare similar hooks and choose the one to fit your situation best. Additionally, we will walk you through creating a custom hook so that you can further take advantage of all hooks have to offer. 

Sharing State 

You will use props and context to share the state between components and to keep up with the state between multiple pages. We will compare the trade-offs between the methods, so you can select which is best for each use case in your application. 

API Integration 

You will practice connecting your app to a server using both API requests and web sockets so that you can send and receive information. You will also learn how to display loading and error states to keep your users in the loop during API interactions. 

Testing 

You will learn how to thoroughly test your React components and flows using React Testing Library. You will also gain experience writing end-to-end tests with Cypress, a powerful testing framework for modern web applications. Additionally, we will cover setting up a mock server to test your application in a controlled environment. By comparing different testing methods, you will learn to choose the most effective approach for your needs. 

Performance Tuning 

Once you’ve completed the two applications and honed your React skills, you will dive into performance optimization. You will discover how to fine-tune your components to ensure your applications respond quickly to user interactions. You will analyze the bundle size of your application and use lazy loading to reduce the time to first contentful paint. You will analyze a large page that responds slowly to user input and use tools like memo, useMemo, useCallback, and useTransition to improve responsiveness. 

Helpful Tools 

There are several community libraries that you will use throughout this book. One of those will be React Router, which you will use to navigate your application. You will use PropTypes to specify the props coming into your components, so you will know if your components receive incorrect props. You will also use ESLint to check your application for coding errors and to enforce coding style. 

Where can you buy the book? 

You can order print and DRM-free electronic copies from InformIT. It is also available from Amazon and other booksellers. 

If you want the whole Big Nerd Ranch experience, enroll in one of our bootcamps or bring us on-site with our corporate training. 

The post Now Available React Programming: The Big Nerd Ranch Guide appeared first on Big Nerd Ranch.

]]>
https://bignerdranch.com/blog/react-programming-the-big-nerd-ranch-guide/feed/ 0
Introduction to Svelte https://bignerdranch.com/blog/introduction-to-svelte/ https://bignerdranch.com/blog/introduction-to-svelte/#respond Thu, 13 Apr 2023 14:00:24 +0000 https://bignerdranch.com/?p=9680 Svelte is a great front-end Javascript framework that offers a unique approach to the complexity of front-end systems. It claims to differentiate itself from other popular frameworks, like React and Angular, by solving these problems rather than moving the complexity around. Some key advantages of Svelte are its impressive performance and speed—and its simple implementation […]

The post Introduction to Svelte appeared first on Big Nerd Ranch.

]]>
Svelte is a great front-end Javascript framework that offers a unique approach to the complexity of front-end systems. It claims to differentiate itself from other popular frameworks, like React and Angular, by solving these problems rather than moving the complexity around. Some key advantages of Svelte are its impressive performance and speed—and its simple implementation that allows for slim files and less boilerplate. For example, with Svelte stores, you can implement full global state management in less than ten lines of code!

Unlike other frameworks, Svelte does not run in the browser, nor does it use the virtual DOM. Instead, it uses a compiler that runs at build time to compile components into standalone JavaScript modules. This approach leads to faster and more efficient applications, making Svelte an excellent choice for building high-performance web applications.

The best way to see all that Svelte offers is to build an app yourself!

Follow along with us to build a Todo app and witness Svelte in action as you implement some of its key features.

 

Getting Started

We assume the reader has Node.js (version 16 or above), a code editor, and a browser installed.

To initialize the todo app, run the following command in your terminal:

npm create vite@4 svelte-todo -- --template=svelte-ts

This command uses the build tool Vite to create and scaffold a Svelte project for you entitled svelte-todo.

This example also adds the option at the end of the command to include TypeScript in your application.

You may be prompted to install create-vite.

Enter y to continue.

To get your project running, follow the steps listed:

  • cd svelte-todo
  • npm install
  • npm run dev -- --open

Congratulations! Your Svelte app is running in your browser at localhost:5173. Open the directory in your code editor. The Vite scaffolding adds a small demo app. To remove it, simply delete these files:

  • ./src/assets
  • ./src/lib
  • ./app.css

Also, perform the following edits:

  • Delete the entire contents of ./src/App.svelte.
  • Remove the line import './app.css' from main.ts.

Create a Component

Let’s create your first Svelte component.

  • First, create a new folder inside the src directory called components.
  • Create a new file in the components folder called TodoItem.svelte.

As the title implies, you are creating a to-do item. We know we will need a checkbox and a description of the item. Svelte components consist of three different parts: JavaScript, HTML, and CSS.

That’s it.

Start by adding the HTML.

<div>
   <input type='checkbox' />
   <span>{item}</span>
</div>

In the code above, you are using familiar HTML tags. There is one question, though: how do you get access to item? Add JavaScript to your component by using script tags. By convention, these typically reside at the beginning of the file.

<script lang="ts">
   export let item: string;
</script>

Variables that will be used by your HTML, like item, are declared inside your script tags. Then, you access them inside brackets like <span>{items}</span>.

In this case, there is an extra keyword: export. This means that the value of item comes from an external source and will be passed into the component as a property. The lang="ts" is optional and denotes that you are using TypeScript inside the tag. That is everything you need for your first component. To see your component in the browser, you need to use it in your application.

Open the file ./src/App.svelte and replace the previous contents of the file:

<script>
   import TodoItem from './components/TodoItem.svelte';
   let todoItems = [
      'Generate Project Skeleton',
      'Create your first component',
      'Create a store',
      'Make a new todo items flow'
   ]
</script>

{#each todoItems as todoItem}
   <TodoItem item={todoItem} />
{/each}

Let’s look at the JavaScript inside the script tags first. The TodoItem component that you created is being imported. Anytime a component is used in another component, it must be imported inside the script tag.

Next, you declare a new variable called todoItems. This is very similar to how the item variable was declared in the TodoItem component, with one big difference. There is no export keyword. This means that this variable is local to this component; the value is not coming from an external source. todoItems is an array that contains a list of items you will accomplish during this tutorial.

Now, take a look at the HTML. This looks different than the HTML you have already seen. That’s because it uses a logic block. In Svelte, you can add logic to HTML by wrapping it in curly braces. The character # lets you know that a logic block is beginning, and the character / signifies the block’s end.

Because todoItems is an array, you can use an each block to iterate through the array and complete an action with each of the items in the array. In this case, you are looking at each item and returning a TodoItem component. Notice that the item is being assigned to the TodoItem component as an attribute-this is how TodoItem has access to the item variable. Check out your application in the browser. You should have a list of items to check off as complete!

Go ahead and check off Generate project skeleton and Create your first component—you’re halfway there!

Stores

Like other frameworks, including React, Svelte has tools for managing global and local state. Unlike the React Context API, the Svelte store does not rely on hierarchy. Components can consume state without being directly nested under provider components. The Svelte store also doesn’t even require that the calling code be Svelte. A store could be consumed through any plain JavaScript module.

Svelte provides three types of stores out-of-the-box writable, readable, and derived. It also provides the ability to create a custom store (you can read more about that at Svelte), but in this tutorial, we will just use a writable store.

Creating a store

Inside /src, create a new directory and file /stores/todo.ts. Inside the new todo.ts file, start by importing the writable store type from svelte/store:

import { writable } from 'svelte/store';

Since this is TypeScript, we must define a type for our store. We could just use a string[], but we want to be able to mark items as done. So, let’s create a type that allows us to define a to-do item and maintain its done status.

In this example, we’re going to export this type because we will need to import it later on in the tutorial, but you may not always need to do this.

export type TodoItemType = {
   item: string;
   done: boolean;
}

Now we can define our store with the default to-do items we used earlier.

export const todoItems = writable<TodoItemType[]>([
   { item: 'Generate project skeleton', done: true },
   { item: 'Create your first component', done: true },
   { item: 'Create a store', done: false },
   { item: 'Make a new todo items flow', done: false },
]);

Consuming the store

Navigate back to App.svelte. Since we’ll be pulling our todo items from a store, we will no longer need the local array todoItems. Let’s replace it with our new store.

<script lang='ts'>
   import TodoItem from './components/TodoItem.svelte';
   import { todoItems } from './stores/todo';
</script>

Now our page is broken because we need to update our loop to use the item key inside the todoItem object we have in our store. Do that now.

{#each todoItems as todoItem}
   <TodoItem item={todoItem.item} />
{/each}

Wait, our page still isn’t displaying our to-do items! That’s because the value of todoItems is a store. It’s not the value of our store. To get that value, we need to subscribe to the store. We can manage subscriptions manually with the subscribe and unsubscribe functions on the store, but this adds quite a bit of additional code.

Thankfully, Svelte offers an easy way to “auto-subscribe” to a store. Auto-subscribing is as simple as prefixing our usage of the store with a $.

{#each $todoItems as todoItem} 
   <TodoItem item={todoItem.item} /> 
{/each}

Look how clean that is!

Writing to the store

Let’s make a new component called AddTodoItem.svelte in the /components directory. This component will handle adding new items to our list. Before we interact with the store, let’s first create our UI. We will want a text input to type out our new item and a button to add it to the store.

<input type='text'/>
<button>Add</button>

We need to maintain our input value locally. If you are familiar with React, you would typically do this by utilizing the useState hook and onChange or onBlur props, but in Svelte we use a concept called binding. We’ll start by defining the variable we want to bind the input value to in a script tag:

<script lang='ts'>
   let todoItem = '';
</script>

Next, we will use bind to bind the value of the text input to todoItem.

<input type='text' bind:value={todoItem} />

Now the value of the variable will be synced with the value of the input, and we’ll be able to use it inside our click handler. So, let’s create a new function and assign it to the on:click event handler for the button.

<script lang='ts'>
   let todoItem = '';
   const addTodoItem = () => {
      alert(todoItem);
   }
</script>

<input type='text' bind:value={todoItem} />
<button on:click={addTodoItem}>Add</button>

Before we can test this in the browser, we need to import and render this component in App.svelte.

<script lang='ts'>
   import TodoItem from './components/TodoItem.svelte';
   import AddTodoItem from './components/AddTodoItem.svelte';
   import { todoItems } from './stores/todo';
</script>

<AddTodoItem />

{#each $todoItems as todoItem}
   <TodoItem item={todoItem.item} />
{/each}

Check out your browser. Type a message in the text box and click “Add”. You should see a browser alert with the message you just typed.

Nice work!

To add a value to the store without overriding what is already there, we will use the update function that exists on the store object. This function takes a function as its only parameter. The parameter function will be passed the current value of the store. We can modify that value and return it to update the store.

Update the script tag in AddTodoItem.svelte:

<script lang='ts'>
  import { todoItems, type TodoItemType } from '../stores/todo';
  let todoItem = '';

  const addTodoItem = () => {
    todoItems.update((store: TodoItemType[]) => (
      [
        ...store,
        {
          item: todoItem,
          done: false
        }
      ]
    ));
  }
</script>

If you want to take it a step further, try updating TodoItem.svelte to toggle the “done” status in the store when a user checks the checkbox.

Styling

Styling in Svelte is scoped to the component the style is defined in. You can accomplish this functionality with other frameworks using things like CSS modules or styled-components, but with Svelte it is included out of the box. So, we don’t have to worry about clashing tag styles or accidentally re-using a class name. These styles also live inside the same file as the component code, typically at the end of the file.

Let’s start by adding some padding to the list of items. Add the following code to the end of TodoItem.svelte:

<style>
   div {
      padding-top: 10px;
   }
</style>

And some styles to AddTodoItem.svelte:

<style>
  button {
    padding: 5px 8px;
    background-color: #b16326;
    color: white;
    border-radius: 5px;
    border: none;
  }

  button:hover {
    background-color: #e38d39;
    cursor: pointer;
  }

  input {
    padding: 5px 8px;
    border-radius: 5px;
    border: 1px solid black;
  }
</style>

Notice our styles assigned to the input tag do not affect the input we have rendered inside TotoItem.svelte.

Conclusion

We’ve gone over the basic concepts of Svelte component structure, binding, stores, and styling. If you want to take things further, take a look at the official Svelte interactive tutorial for some more advanced topics, and be on the lookout for more Svelte blog posts!

The post Introduction to Svelte appeared first on Big Nerd Ranch.

]]>
https://bignerdranch.com/blog/introduction-to-svelte/feed/ 0
Learn the Lifecycle of a Web Component by Building a Custom Element https://bignerdranch.com/blog/learn-the-lifecycle-of-a-web-component-by-building-a-custom-element/ https://bignerdranch.com/blog/learn-the-lifecycle-of-a-web-component-by-building-a-custom-element/#respond Wed, 26 Jan 2022 17:19:59 +0000 https://bignerdranch.com/?p=9266 Did you know you can create your own html tags? That is exactly what customElements.define() provides. In this post you will learn about the lifecycle of a web component.

The post Learn the Lifecycle of a Web Component by Building a Custom Element appeared first on Big Nerd Ranch.

]]>
What are Web Components?

Web components are a web standard that was first introduced in 2011 but have not seen much adoption. Adopting web standards creates a future-proof solution because the web is built to be backward compatible. Custom elements are part of the web component ecosystem, and the lifecycle methods of a custom element are key to creating the desired UI experience. The following is an exploration of the available lifecycle methods and how they could be used when creating a custom button component. The button component used in this blog post is part of a larger photo gallery demo. The full code for the photo gallery can be found here. We also have a demo available. Explore the photo gallery code base and demo to learn more about web components.

TL;DR

This is the button that will be built in this post with all available lifecycle methods:

const template = document.createElement("template");
template.innerHTML = `<button id="button">Click ME</button>`;

customElements.define(
  "wc-button",
  class extends HTMLElement {
    constructor() {
      super();
      this.attachShadow({ mode: "open" });
      this.shadowRoot.appendChild(template.content.cloneNode(true));
    }

    connectedCallback() {
      this.addEventListener("click", this.onclick);
    }

    adoptedCallback() {
      console.log(“moved to a new document”);
    }

    disconnectedCallback() {
      this.removeEventListener("click", this.onclick);
    }

    static get observedAttributes() {
      return ["disabled"];
    }

    set disabled(bool) {
      this.setAttribute("disabled", bool.toString());
    }

    get disabled() {
      return this.getAttribute("disabled") === "true";
    }

    attributeChangedCallback(attrName, oldVal, newVal) {
      switch (attrName) {
        case "disabled": {
          this.shadowRoot.getElementById("button").disabled = newVal === "true";
          break;
        }
        default: {
          console.log("unhandled attribute change", attrName, oldVal, newVal);
          break;
        }
      }
    }

    onclick() {
      const button = this.shadowRoot.getElementById("button");
      if (event.composedPath().includes(button)) {
        console.log("button clicked");
      }
    }
  },
);

Defining Custom Elements

In order to register a web component, you must define a Custom Element. To define a custom HTML element, use customElements.define(). This function registers a custom element that extends the HTMLElement interface, a native browser API. customElements.define() takes three parameters: the name of the custom element, the constructor for that element, and an optional options object. As of this writing, the options object only supports a single option called extends which is used to specify the name of a built-in element to extend in order to create a customized built-in element. In this example, the name of the custom element is wc-button and the second parameter is the element class.

customElements.define(
  "wc-button",
  class extends HTMLElement {
    // ...
  }
);

It is important to note that the name of a custom element must include a dash to avoid naming conflicts with any built-in HTML elements. Additionally, custom elements need a closing tag because there are only a few HTML elements that can be self-closing. Custom elements can be imported into HTML files inside a <script type="module"> tag and then used in the same manner as any standard HTML element. Setting the type attribute equal to module is important in order to declare the script as a JavaScript module, and for the component to be imported properly.

<html>
  <head>
    <script type="module">
      import "/button.js";
    </script>
  </head>
  <body>
    <wc-button></wc-button>
  </body>
</html>

constructor()

The constructor is defined within the class to define a custom element. Generically, the constructor is a method used to create and initialize an object instance of that class. In the web component lifecycle, the constructor is the first method of the lifecycle and is called once the web component is initialized. The first method called in the constructor is super, a keyword used to access and call functions on the parent object. super must be called first in order to access this and establish the correct prototype chain. In this case, the parent element being accessed is HTMLElement, a class that provides a standard set of properties, event handlers, methods, and events.

Using the Shadow DOM provides encapsulation of the HTML, CSS, and behavior of the web component keeping it hidden from other elements on the same web page.

const template = document.createElement("template");
template.innerHTML = `<button id="button">Click ME</button>`;

customElements.define(
  "wc-button",
  class extends HTMLElement {
    constructor() {
      super();
      this.attachShadow({ mode: "open" });
      this.shadowRoot.appendChild(template.content.cloneNode(true));
    }
  }
);

Following super, a shadow root is created and attached to the custom element thereby creating an internal shadow DOM structure. When attaching the custom element to the shadow root, the mode must be set to open. When open, the shadow DOM can be accessed using JavaScript. However, when closed, the shadow DOM cannot be accessed from the outside. Once attached, content can be added to the shadow DOM via this.shadowRoot. For example, here the template content is appended to the shadow root using this.shadowRoot.appendChild().

connectedCallback()

The connectedCallback() method will be called once each time the web component is attached to the DOM. Since the shadow root was attached in the constructor(), then connectedCallback() can be used to access attributes, child elements, or attach event listeners. If the component is moved or removed and re-attached to the DOM, then connectedCallback() will be called again.

customElements.define(
  "wc-button",
  class extends HTMLElement {
    // ...
    connectedCallback() {
      this.addEventListener("click", this.onclick);
    }

    onclick() {
      console.log("clicked handled");
    }
  }
);

In the button example, the connectedCallback() lifecycle method is used to add a click event listener to the component.

attributeChangedCallback()

To use the attributeChangedCallback() method, the attributes to be observed must first be defined in a static method called observedAttributes(). This method returns an array of the attribute names.

Once the attribute has been returned from observedAttributes(), the lifecycle method attributeChangedCallback() will be called every time that attribute is updated. This method has three parameters: the attribute name being changed, the old value of that attribute, and the updated value. Attributes are updated when this.setAttribute() is triggered.

customElements.define(
  "wc-button",
  class extends HTMLElement {
    // ...
    static get observedAttributes() {
      return ["disabled"];
    }
    attributeChangedCallback(attrName, oldVal, newVal) {
      if (attrName === "disabled") {
        this.shadowRoot.getElementById("button").disabled = newVal === "true";
      }
    }
    set disabled(bool) {
      this.setAttribute("disabled", bool.toString());
    }
    get disabled() {
      return this.getAttribute("disabled") === "true";
    }
  }
);
<html>
  <head>
    <script type="module" src="./button.js"></script>
  </head>
  <body>
    <script>
      document.querySelector("wc-button").disabled = true;
    </script>
  </body>
</html>

 

This example watches the custom element’s disabled attribute; when that attribute is changed, the node’s disabled property is also updated.

Attributes are stored as serialized data. getters and setters can be defined on the class to handle serializing and deserializing data on storage and retrieval.

adoptedCallback()

The adoptNode() method is used to move a node from one document to another. This is often used when working with iFrame components. adoptedCallback() is triggered when document.adoptNode() is used to move the web component to a new document.

customElements.define(
  "wc-button",
  class extends HTMLElement {
    // ...
    adoptedCallback() {
      console.log(“moved to a new document”);
    }
  }
);


document.adoptNode(
  document.getElementById("iframe").contentDocument.getElementById("wc-button")
);

disconnectedCallback()

The disconnectedCallback() method will be called when the web component is removed from the DOM.

customElements.define(
  "wc-button",
  class extends HTMLElement {
    // ...
    disconnectedCallback() {
      this.removeEventListener("click", this.onclick);
    }
  }
);
document.body.removeChild(document.getElementById("wc-button"));

In the button example, this lifecycle method is used to clean up and remove the click event listener.

Conclusion

This custom button element can be reused throughout a project. To recap, when building web components, first the custom element must be registered using customElements.define(). Then, once initialized, the constructor() is called to append the node to the shadow DOM. When the element is attached, the connectedCallback() is triggered and is used to attach an event listener. Each time the disabled attribute on the element is updated, the attributeChangedCallback() is triggered. If moved to another document, the adoptedCallback() method will be used. Finally, when removed from the DOM, the disconnectedCallback() method is called to clean up the event listener.

The post Learn the Lifecycle of a Web Component by Building a Custom Element appeared first on Big Nerd Ranch.

]]>
https://bignerdranch.com/blog/learn-the-lifecycle-of-a-web-component-by-building-a-custom-element/feed/ 0