Preact
Preact is an alternative to React with the same modern API.
Preact components are packaged using Webpacker and the
Preact code is located in app/javascript
.
Preact components get loaded via webpacker's helper function
javascript_packs_with_chunks_tag
.
How we use Preact
Our approach to Preact follows the Islands Architecture pattern: we render as much as we can server-side, and then use Preact to enhance the parts of that server-rendered page that require richer interactivity. Preact is used to either render new content into a placeholder container in the HTML, or (preferably) to replace a server-rendered piece of UI with one that offers a richer experience.
Example: Preact <ColorPicker />
We have a Preact <ColorPicker />
component which offers both a popover color picker, and a plain text input for a color. When we use this component, we first render a plain text input server-side. This text input is fully functional, and if no JavaScript is loaded, a user can still complete the hex code of their choice. When the page loads, we asynchronously find these plain text inputs and dynamically replace them with the richer Preact experience.
PropTypes
Preact supports PropTypes. When creating Preact components, please ensure that you have defined your PropTypes.
Common PropTypes
Using PropTypes can be repetitive. Some duplication is normal, like when a
PropType is a string or a number. But for commonly-used PropTypes, like the user
entity, you can use the provided common PropTypes, located in the
/app/javascript/common-prop-types
, as shown below.
import PropTypes from "prop-types";
export const userPropTypes = PropTypes.shape({
id: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
profile_image_url: PropTypes.string.isRequired,
summary: PropTypes.string.isRequired,
});
Using Common PropTypes
Common PropTypes are imported just like any other
JavaScript Module.
For example, here are two scenarios where a component needs to use the
tagPropTypes
.
In the example below, our component SomeComponentUsingTags
has a tags
prop,
which is an array of the tag entity. PropTypes have a built-in method called
arrayOf
that allows you to define a prop as an array of something. In our
case, this is the tag entity, so we can use the tagPropTypes
PropType.
import { h } from "preact";
import PropTypes from "prop-types";
import { tagPropTypes } from "../../../components/common-prop-types";
const SomeComponentUsingTags = ({ tags = [] }) => (
<ul>
{tags.map((tag) => (
<li key={tag.id}>{tag.name}</li>
))}
</ul>
);
SomeComponentUsingTags.displayName = "SomeComponentUsingTags";
SomeComponentUsingTags.propTypes = {
tags: PropTypes.arrayOf(tagPropTypes).isRequired,
};
In the following example, the SomeComponentUsingOneTag
component has a tag
prop representing a single tag. In this case, we can just the tagPropTypes
on
their own to represent the shape of the tag
prop.
import { h } from "preact";
import { tagPropTypes } from "../../../components/common-prop-types";
const SomeComponentUsingOneTag = ({ tag }) => <li key={tag.id}>{tag.name}</li>;
SomeComponentUsingOneTag.displayName = "SomeComponentUsingTags";
SomeComponentUsingOneTag.propTypes = {
tag: tagPropTypes.isRequired,
};