Categories
Preact

Preact — Using Web Components

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.

Web Components

We can render web components in our Preact component.

For example, we can write:

import { Component, render } from "preact";

window.customElements.define(
  "x-foo",
  class extends HTMLElement {
    constructor() {
      super();
      let tmpl = document.createElement("template");
      tmpl.innerHTML = `
        <b>I am in the shadown dom</b>
        <slot></slot>
      `;
      let shadowRoot = this.attachShadow({ mode: "open" });
      shadowRoot.appendChild(tmpl.content.cloneNode(true));
    }
  }
);

export default class App extends Component {
  render() {
    return <x-foo position={{ x: 10, y: 20 }}>foo bar</x-foo>;
  }
}
if (typeof window !== "undefined") {
  render(<App />, document.getElementById("root"));
}

We call customElements.define to create our web component.

Then we reference it in the App component and add our content inside the slot .

We can use the x and y properties by writing:

import { Component, render } from "preact";

window.customElements.define(
  "x-foo",
  class extends HTMLElement {
    constructor() {
      super();
      let tmpl = document.createElement("template");
      tmpl.innerHTML = `
        <b>I am in the shadown dom</b>
        <slot></slot>
      `;
      let shadowRoot = this.attachShadow({ mode: "open" });
      shadowRoot.appendChild(tmpl.content.cloneNode(true));
    }

    set position({ x, y }) {
      this.style.cssText = `left:${x}px; top:${y}px; position: absolute`;
    }
  }
);

export default class App extends Component {
  render() {
    return <x-foo position={{ x: 10, y: 20 }}>foo bar</x-foo>;
  }
}
if (typeof window !== "undefined") {
  render(<App />, document.getElementById("root"));
}

We add the position setter.

Then we set the this.style.cssText property to set the position of the x-foo component.

Therefore, the x-foo component has the position values applied to it.

We can also call methods in web component classes.

To do this, we assign a ref to the web component.

Then we can call the methods in the web component class:

import { render } from "preact";
import { useEffect, useRef } from "preact/hooks";

window.customElements.define(
  "x-foo",
  class extends HTMLElement {
    constructor() {
      super();
      let tmpl = document.createElement("template");
      tmpl.innerHTML = `
        <b>I am in the shadown dom</b>
        <slot></slot>
      `;
      let shadowRoot = this.attachShadow({ mode: "open" });
      shadowRoot.appendChild(tmpl.content.cloneNode(true));
    }

    set position({ x, y }) {
      this.style.cssText = `left:${x}px; top:${y}px; position: absolute`;
    }

    doSomething() {
      console.log("did something");
    }
  }
);

export default function App() {
  const myRef = useRef(null);

  useEffect(() => {
    if (myRef.current) {
      myRef.current.doSomething();
    }
  }, []);

  return <x-foo ref={myRef} />;
}
if (typeof window !== "undefined") {
  render(<App />, document.getElementById("root"));
}

We set the ref prop to the myRef ref object, which is created from the useRef hook.

Then in the useEffect callback, we call myRef.current.doSomething() method to call the doSomething method in the web component.

Listen to Web Component Events

We can listen to web components. For example, we can write:

import { render } from "preact";
import { useEffect, useRef } from "preact/hooks";

window.customElements.define(
  "x-foo",
  class extends HTMLElement {
    constructor() {
      super();
      let tmpl = document.createElement("template");
      tmpl.innerHTML = `
        <b>I am in the shadown dom</b>
        <slot></slot>
      `;
      let shadowRoot = this.attachShadow({ mode: "open" });
      shadowRoot.appendChild(tmpl.content.cloneNode(true));
    }

    set position({ x, y }) {
      this.style.cssText = `left:${x}px; top:${y}px; position: absolute`;
    }

    connectedCallback() {
      this.shadowRoot.addEventListener("click", function (e) {
        console.log("listend to click event");
        console.log(e);
      });
    }
  }
);

export default function App() {
  return <x-foo onclick={() => console.log("click")}>foo bar</x-foo>;
}
if (typeof window !== "undefined") {
  render(<App />, document.getElementById("root"));
}

We call addEventListener to add the click event listener to our web component.

And we set the onclick prop to assign an event listener for the click event.

So when we click on the text, we should see the console log from both event listeners called.

Conclusion

We can use web components directly in our Preact app.

Categories
Preact

Preact — Checkboxes, Radio Buttons, and Refs

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.

Checkboxes and Radio Buttons

We can add checkboxes or radio buttons and get their selected values.

For example, we can write:

import { Component, render } from "preact";

export default class App extends Component {
  toggle = (e) => {
    let checked = !this.state.checked;
    this.setState({ checked });
  };

  render(_, { checked }) {
    return (
      <label>
        <input type="checkbox" checked={checked} onClick={this.toggle} />
      </label>
    );
  }
}
if (typeof window !== "undefined") {
  render(<App />, document.getElementById("root"));
}

We create the checked state.

Then we pass that into the checked prop.

The onClick prop is set to the toggle method.

And we call setState to set the checked state.

We can add radio buttons by writing:

import { Component, render } from "preact";

export default class App extends Component {
  constructor() {
    super();
    this.state = {
      fruit: "apple"
    };
  }

onChangeValue = (event) => {
    this.setState({ fruit: event.target.value });
  };

render(_, { fruit }) {
    return (
      <div onChange={this.onChangeValue}>
        <input
          checked={fruit === "apple"}
          type="radio"
          value="apple"
          name="fruit"
        />{" "}
        apple
        <input
          checked={fruit === "orange"}
          type="radio"
          value="orange"
          name="fruit"
        />{" "}
        orange
        <input
          checked={fruit === "grape"}
          type="radio"
          value="grape"
          name="fruit"
        />{" "}
        grape
      </div>
    );
  }
}
if (typeof window !== "undefined") {
  render(<App />, document.getElementById("root"));
}

We add the radio buttons.

Then we watch for changes in radio button selection with the onChange callback.

In the onChangeValue method, we call setState to set the fruit state.

In the input s, we set the checked prop to set the checked state of the radio button.

We get the fruit state from the render method and check against that to set the checked state.

createRef

We call the createRef function to return a plain object with the current property.

Whenever the render method is called, Preact will assign the DOM node or component to current .

For example, we can write:

import { Component, createRef, render } from "preact";

export default class App extends Component {
  ref = createRef();

  componentDidMount() {
    console.log(this.ref.current);
  }

  render() {
    return <div ref={this.ref}>foo</div>;
  }
}
if (typeof window !== "undefined") {
  render(<App />, document.getElementById("root"));
}

to assign our ref to the div.

So when we log this.ref.current , we’ll see the div logged.

Callback Refs

We can also get a reference to an element by passing in a callback function.

For example, we can write:

import { Component, render } from "preact";

export default class App extends Component {
  ref = null;
  setRef = (dom) => (this.ref = dom);

  componentDidMount() {
    console.log(this.ref);
  }

  render() {
    return <div ref={this.setRef}>foo</div>;
  }
}
if (typeof window !== "undefined") {
  render(<App />, document.getElementById("root"));
}

We have the setRef function with the dom parameter, which has the DOM node that we passed this function as the value of ref to.

Since we passed it in as the value of the ref prop in the div, the div is dom ‘s value.

We assigned it to this.ref so that we can access it.

And in the componentDidMount hook, we log the value of this.ref and we see that its value is the div.

Conclusion

We can add checkboxes and radio buttons easily with Preact.

And we can get DOM elements with refs.

Categories
Preact

Preact — Form Inputs and Dropdowns

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.

Forms

We can handle form inputs in Preact as we do with plain JavaScript and HTML.

We can create uncontrolled components, which are input components where we don’t manage the value of the input.

For example, we can write:

import { render } from "preact";

export default function App() {
  return (
    <div>
      <input onInput={(e) => console.log(e.target.value)} />;
    </div>
  );
}
if (typeof window !== "undefined") {
  render(<App />, document.getElementById("root"));
}

to add an uncontrolled input component.

We get the input value from the e.target.value property but we don’t set the value prop with it.

To create a controlled component, we can set the value prop of it:

import { render } from "preact";
import { useState } from "preact/hooks";

export default function App() {
  const [value, setValue] = useState();
  return (
    <div>
      <p>{value}</p>
      <input value={value} onInput={(e) => setValue(e.target.value)} />;
    </div>
  );
}
if (typeof window !== "undefined") {
  render(<App />, document.getElementById("root"));
}

The onInput callback calls setValue to set the value state.

Then we display value and pass it into the value prop of the input.

Creating A Simple Form

We can create a simple form easily with Preact.

For instance, we can write:

import { Component, render } from "preact";

export default class App extends Component {
  state = { value: "" };

  onSubmit = (e) => {
    alert("Submitted");
    e.preventDefault();
  };

  onInput = (e) => {
    const { value } = e.target;
    this.setState({ value });
  };

  render(_, { value }) {
    return (
      <form onSubmit={this.onSubmit}>
        <input type="text" value={value} onInput={this.onInput} />
        <p>You typed this value: {value}</p>
        <button type="submit">Submit</button>
      </form>
    );
  }
}
if (typeof window !== "undefined") {
  render(<App />, document.getElementById("root"));
}

We created a component class that has the onSubmit method that’s used as the value of the onSubmit prop.

It’ll be called when we click Submit.

The input calls onInput when we enter something.

We get the value entered with the e.target.value property.

We get the value state from the 2nd parameter of the render function.

Select Input

We can add a select input with code similar to the previous example.

For example, we can write:

import { Component, render } from "preact";

export default class App extends Component {
  state = { value: "" };

  onChange = (e) => {
    this.setState({ value: e.target.value });
  };

  onSubmit = (e) => {
    alert("Submitted " + this.state.value);
    e.preventDefault();
  };

  render(_, { value }) {
    return (
      <form onSubmit={this.onSubmit}>
        <select value={value} onChange={this.onChange}>
          <option value="A">A</option>
          <option value="B">B</option>
          <option value="C">C</option>
        </select>
        <button type="submit">Submit</button>
      </form>
    );
  }
}
if (typeof window !== "undefined") {
  render(<App />, document.getElementById("root"));
}

to add a select element into our App component.

We listen to the change event with the onChange callback.

And we set the value prop to the value state.

When we click Submit, the onSubmit method runs.

And we see the alert displayed with the value that we selected.

Conclusion

We can add form inputs and dropdowns easily with Preact.

Categories
Preact

Preact — Side Effect Hooks

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.

useEffect

We use the useEffect hook to commit side effects.

For example, we can write:

import { render } from "preact";
import { useEffect } from "preact/hooks";

function PageTitle({ title }) {
  useEffect(() => {
    document.title = title;
  }, [title]);

  return <h1>{title}</h1>;
}

export default function App() {
  return (
    <div>
      <PageTitle title="hello world" />
    </div>
  );
}
if (typeof window !== "undefined") {
  render(<App />, document.getElementById("root"));
}

We have the PageTitle component which takes the title prop.

Then we can watch the value of that with the useEffect hook’s 2nd argument.

And we set the document.title to the title prop’s value.

We can also use it to listen to events when we mount the component and unbind the event handler when we unmount it.

For example, we can write:

import { render } from "preact";
import { useEffect, useState } from "preact/hooks";

export default function App() {
  const [width, setWidth] = useState(0);

  function onResize() {
    setWidth(window.innerWidth);
  }

  useEffect(() => {
    window.addEventListener("resize", onResize);
    return () => window.removeEventListener("resize", onResize);
  }, []);

  return <div>Window width: {width}</div>;
}
if (typeof window !== "undefined") {
  render(<App />, document.getElementById("root"));
}

We have the width state to set the window’s width.

onResize calls setWidth to set the width.

In the useEffect hook, we call window.addEventListener to listen to the resize event.

And we return the callback to remove the listener when we unmount the component.

Then we show the width in the div .

Now when we resize the window, we’ll see the width number change.

useLayoutEffect

useLayoutEffect has the same signature as useEffect , but it’ll fire as soon as the component is diffed and the browser has a chance to paint.

useErrorBoundary

The useErrorBoundary hook lets us catch errors when a child component throws an error.

Then we can catch them with this hook.

For example, we can write:

import { render } from "preact";
import { useErrorBoundary } from "preact/hooks";

const Child = () => {
  if (Math.random() < 0.5) {
    throw new Error("error");
  }
  return <p>child</p>;
};

const Parent = ({ children }) => {
  const [error, resetError] = useErrorBoundary();

  if (error) {
    return (
      <div>
        <p>{error.message}</p>
        <button onClick={resetError}>Try again</button>
      </div>
    );
  } else {
    return <div>{children}</div>;
  }
};

export default function App() {
  return (
    <div>
      <Parent>
        <Child />
      </Parent>
    </div>
  );
}
if (typeof window !== "undefined") {
  render(<App />, document.getElementById("root"));
}

We have the Child component that randomly throws an error.

And we have the Parent component that renders child components if there’s no error thrown in child components.

If there’re errors throw in child components, then we show the error and show a button to run the resetError function when we click it.

resetError remounts the component.

So when we when an error raised in Child , we can click Try Again to refresh the child components.

Conclusion

We can use the useEffect hook to commit side effects.

Categories
Preact

Preact — Memoization, Callbacks, and Context Hooks

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.

Memoization

We can use the useMemo hook to store results of expensive computations.

For example, we can write:

import { render } from "preact";
import { useMemo, useState } from "preact/hooks";

const expensive = (a, b) => {
  //...
};

function App() {
  const [a, setA] = useState(0);
  const [b, setB] = useState(0);
  const memoized = useMemo(() => expensive(a, b), [a, b]);
  //...
  return (
    <div>
      <p>{memoized}</p>
    </div>
  );
}

if (typeof window !== "undefined") {
  render(<App />, document.getElementById("root"));
}

We have the expensive function that does some expensive operation.

We call it in the useMemo callback to cache its result.

memoized is only computed again when a or b is changed.

We shouldn’t commit any side effects in useMemo .

If we need to commit side effects, we should use useEffect .

useCallback

The useCallback hook lets us ensure that the returned function is referentially equal until the dependencies change.

For example, we can write:

import { render } from "preact";
import { useCallback, useState } from "preact/hooks";
function App() {
  const [count, setCount] = useState(0);
  const increment = () => setCount(count + 1);
  const decrement = () => setCount((currentCount) => currentCount - 1);

  const log = useCallback(() => console.log(count), [count]);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={log}>log</button>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
}
if (typeof window !== "undefined") {
  render(<App />, document.getElementById("root"));
}

We pass in a callback into the useCallback hook to cache the callback until the count state changes.

This lets us prevent the callback from recreated every time the component renders.

useRef

The useRef hook lets us get a reference to a DOM node in a function component.

For instance, we can write:

import { render, Fragment } from "preact";
import { useRef } from "preact/hooks";

function App() {
  const input = useRef(null);
  const onClick = () => input.current && input.current.focus();

  return (
    <>
      <input ref={input} />
      <button onClick={onClick}>Focus input</button>
    </>
  );
}
if (typeof window !== "undefined") {
  render(<App />, document.getElementById("root"));
}

We call the useRef hook to return a ref.

Then we assign it to the input with the ref prop.

We also create the onClick function to get the input element with the input.current property and call focus on it.

So when we click on Focus Input, the input will be focused.

useContext

The useContext hook lets us access a context in a function component.

For example, we can write:

import { createContext, render, Fragment } from "preact";
import { useContext } from "preact/hooks";

const Theme = createContext("light");

function DisplayTheme() {
  const theme = useContext(Theme);
  return <p>Active theme: {theme}</p>;
}

function SomeComponent({ children }) {
  return <>{children}</>;
}

export default function App() {
  return (
    <div>
      <Theme.Provider value="dark">
        <SomeComponent>
          <DisplayTheme />
        </SomeComponent>
      </Theme.Provider>
    </div>
  );
}

if (typeof window !== "undefined") {
  render(<App />, document.getElementById("root"));
}

We call createContext to create the Theme context.

Then we render the Theme.Provider in app to set the value of the context.

And we can get the Theme context value with the useContext hook in the DisplayTheme component.

We pass in the context that we want to access.

If our component is inside the Theme.Provider then we can access its value.

Conclusion

We can use hooks to memorize data, cache callbacks, and share data between components with Preact.