Preact — Class Components and Fragments

John Au-Yeung - Jan 22 '21 - - Dev Community

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

Preact is a front end web framework that’s similar to React.

It’s smaller and less complex than React.

In this article, we’ll look at how to get started with front end development with Preact.

Class Components

We can add class components as we do with React.

For example, we can write:

import { Component, render } from "preact";

class Clock extends Component {
  constructor() {
    super();
    this.state = { time: Date.now() };
  }

  componentDidMount() {
    this.timer = setInterval(() => {
      this.setState({ time: Date.now() });
    }, 1000);
  }

  componentWillUnmount() {
    clearInterval(this.timer);
  }

  render() {
    const time = new Date(this.state.time).toLocaleTimeString();
    return <span>{time}</span>;
  }
}
if (typeof window !== "undefined") {
  render(<Clock />, document.getElementById("root"));
}
Enter fullscreen mode Exit fullscreen mode

We create the Clock component by creating a class that extends the Component class.

Then in the constructor , we create the time state and set it to Date.now() as the initial value.

The componentDidMount hook lets us initialize the data.

In the method, we call setInterval to create the timer and in the callback, we call setState to set the state.

componentWillUnmount is called when we unmount the component, so we call clearInterval to clear the timer when the component unmounts.

In the render method, we render the current time.

Preact methods include lifecycle methods that are included in React class components.

They include:

  • componentDidMount() — after the component gets mounted to the DOM
  • componentWillUnmount() — prior to removal from the DOM
  • getDerivedStateFromProps(nextProps) — just before shouldComponentUpdate. Use with care.
  • shouldComponentUpdate(nextProps, nextState) — before render(). Return false to skip render
  • getSnapshotBeforeUpdate(prevProps, prevState) — called just before render(). The return value is passed to componentDidUpdate.
  • componentDidUpdate(prevProps, prevState, snapshot) — after render()

Fragments

We can use the Fragment component to render multiple components without a root element.

For example, we can write:

import { Fragment, render } from "preact";

function TodoItems() {
  return (
    <Fragment>
      <li>foo</li>
      <li>bar</li>
      <li>baz</li>
    </Fragment>
  );
}

const App = (
  <ul>
    <TodoItems />
    <li>qux</li>
  </ul>
);

if (typeof window !== "undefined") {
  render(App, document.getElementById("root"));
}
Enter fullscreen mode Exit fullscreen mode

We have the TodoItems component, which renders a Fragment .

The resulting HTML only has the li elements.

In App , we combine TodoItems with li and render them together.

We can use <> and </> in place of <Fragment> and </Fragment> :

import { Fragment, render } from "preact";

function TodoItems() {
  return (
    <>
      <li>foo</li>
      <li>bar</li>
      <li>baz</li>
    </>
  );
}

const App = (
  <ul>
    <TodoItems />
    <li>qux</li>
  </ul>
);

if (typeof window !== "undefined") {
  render(App, document.getElementById("root"));
}
Enter fullscreen mode Exit fullscreen mode

We can also return an array of components:

import { Fragment, render } from "preact";

function TodoItems() {
  return [<li>foo</li>, <li>bar</li>, <li>baz</li>];
}

const App = (
  <ul>
    <TodoItems />
    <li>qux</li>
  </ul>
);

if (typeof window !== "undefined") {
  render(App, document.getElementById("root"));
}
Enter fullscreen mode Exit fullscreen mode

This is the same as what we have before.

If we use Fragment s in a loop, then we have to add the key prop and set it to a unique value so that the items can be distinguished:

import { Fragment, render } from "preact";

const items = [
  {
    id: 1,
    term: "apple",
    description: "red fruit"
  },
  {
    id: 2,
    term: "banana",
    description: "yellow fruit"
  }
];

function Glossary({ items }) {
  return (
    <dl>
      {items.map((item) => (
        <Fragment key={item.id}>
          <dt>{item.term}</dt>
          <dd>{item.description}</dd>
        </Fragment>
      ))}
    </dl>
  );
}

const App = (
  <div>
    <Glossary items={items} />
  </div>
);

if (typeof window !== "undefined") {
  render(App, document.getElementById("root"));
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

We can create class components and fragments as we do with React.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .