DEV Community

A beginner's tutorial to Preact - Part 4: First steps with Preact

Now that we have reviewed everything we need to know prior to launching ourselves with Preact.

What is Preact?

Preact is a 3kb library which allows developers to write applications using the same patterns we saw earlier. Preact provides its own implementation of the h function which outputs Virtual DOM (the "pure JavaScript representation of DOM nodes" we have talked about earlier), and uses an efficient rendering algorithm to try and make as few changes to the web page as possible. It also boasts many more features that we will look at later.

The canonical "Hello World" application

Dependencies

Let's start by creating a project. I'm going to use CodeSandbox (as I have already for the examples) as it allows me to embed the project into the post directly for you to run and tweak. So, either start a new "Vanilla (+ TS)" project, or start a new npm project (npm init).

The second thing to do, of course, is to install Preact. We're going to use version 10, which at the time of writing is still in Release Candidate, but is a complete rewrite of Preact itself, and writing a tutorial with a well known expire date isn't all that useful. Use preact@next if in beta, or just preact if you're reading this after version 10 was released as stable.

Next, if you're not using CodeSandbox, install Parcel as a development dependency: npm i --save-dev parcel, and optionally TypeScript (npm i --save-dev typescript). This is to replicate the CodeSandbox environment

The index.html file

Next, we're going to need to create a basic index file for the browser to load - it will point to the script, and have an identified div element for us to render the application in.

CodeSandbox already provides that by default, although we'll need to change the script extension from js to jsx (or ts to tsx).

Here's the contents of index.html

<html>
  <head>
    <title>Parcel Sandbox</title>
    <meta charset="UTF-8" />
  </head>

  <body>
    <div id="app"></div>

    <script src="src/index.tsx"></script>
  </body>
</html>

The JavaScript entry-point of the application

Next, we need to create the file referenced in the script element - CodeSandbox users can rename the existing file in src, while local users can just create it at src/index.jsx or src/index.tsx.

Eitherway, if any, remove all contents, and let's start with our necessary imports:

import {h, render} from "preact";

Here, we import Preact's implementation of the h function, and also a render function - we'll use that later.

Our first component

Next, we need to write something for Preact to render. For this we need to write a component. We'll talk more about components in the next part, but in short, components are the reusable pieces of code that ca be passed props, and have state - they are the reusable elements that are at the base of reusability in modern JavaScript framework applications.

Components come in two variants - function-based, or class-based. More and more projects use function-based components, especially now that Hooks are getting more popular (more on that later). We'll use a function-based component, and name it Application. Let's add it in our index file:

function Application() {
  return <p>Hello world!</p>;
}

That's it. This function accepts no props (as they are given through the arguments), and simply return a paragraph element (actually, it's Virtual DOM equivalent).

We need to use that new component somewhere, and that's why we also have imported the render function.

Rendering our component

Since Preact deals with Virtual DOM through its h function, we need a way for that Virtual DOM to become, well, real. This is what the render function does - it inputs a Virtual DOM node, and a DOM element to insert the generated DOM into. We already have a div tag in our index.html made for the purpose of hosting our application - so let's use that. Then, we need a Virtual DOM node to pass into the render, and that Virtual DOM will come from our component. Remember that Preact's h function returns Virtual DOM, but what you may not know (but probably have guessed), is that the function can also take components instead of tag name as first parameter. This is how we reuse components in Preact. And, where we can use h, we can also write JSX - therefore that's how we'll pass the Application component to the render function.

Anyhow, let's get some generated DOM into our web page. We'll get a reference to the <div id="app"> element in the DOM, and pass it to the render function:

const root = document.getElementById("app");
render(<Application/>, root);

Our component displays "Hello World!" onto the web page! ๐Ÿ”ฅ

Nesting components

Let's create more components, shall we?

Components are good for several things - but at their most basic, they allow to create reusable elements; for example, a button component we'll write next.

Leaving the implementation to next part, let's use this hypothetical Button component into our application. We want this component to be customizable to a certain degree, which can be done through propertiess. We can pass any value through those props, which includes functions (as functions are values). This will be useful in keeping our Button component generic and therefore reusable - we will expose a "onClick" prop which expects a callback function which will get called when the user clicks on the component.

Let's use this specification for the accepted properties (often abbreviated as props) of this Button component:

interface ButtonProps {
  /** Any CSS color string, from names to hex codes to HSL, HSV or RGB(A) functions */
  color: string;
  /** Changes the button elevation by altering the shadow property of the button */
  elevated?: boolean;
  /** Callback function which gets called when the user clicks on the button */
  onClick?: (ev: MouseEvent) => void;
}

Note: This is valid TypeScript which I use in the source code to define the component properties, see the CodeSandbox examples

With this, we can create an application with two buttons to showcase how they can each be customized separatedly. In the following code, each button gets assigned a random color; the first button has a callback which shows an alert box on click while the second doesn't have any callback; also only the first button is elevated (as it is by default), the second button has its elevation turned off.

Below is the code with its accompanying CodeSandbox example:

function Application() {
  const color1 = colors[Math.round(Math.random() * colors.length)];
  const color2 = colors[Math.round(Math.random() * colors.length)];
  return (
    <div>
      <p>Hello world!</p>
      <Button color={color1} onClick={() => alert("First button was clicked!")}>
        Learn more
      </Button>
      <Button color={color2} elevated={true}>
        Another button
      </Button>
    </div>
  );
}

In the next part

We will look at how to implement this Button component (though you can peek into the CodeSandbox source code by yourself if you want to figure it out). We'll cover the two ways to write components, as well as several useful techniques.

Top comments (0)