Components
The theme's built like a SPA, in that the page doesn't fully reload on page shifts.
In order to keep the components on the site hydrated, there's a few framework-functions to handle this.
Each component your make should be a function following the type of Component
:
ts
type Refs = Record<string, HTMLElement[]>
export type CleanupFunction = (() => unknown) | (() => unknown)[]
export type Component = (
ref: Refs,
opts?: {
// used to remove event listeners on page shift
signal?: AbortSignal
}
) => CleanupFunction | Promise<CleanupFunction> | void
declare global {
interface Window {
Shopify: {
designMode: unknown
}
forceNavigationRefresh: boolean
navigation: any
}
}
Each function has access to 2 arguments. The first is the result of useRefs()
, and the other is an object containing an AbortSignal
that is used to remove event listeners.
Examples
Standard
This is how a typical component could look like:
liquid
<button data-ref='my-button'>My button</button>
ts
// /frontend/components/my-component.ts
import { Component } from '~/types'
const component: Component = (ref, { signal = null } = {}) => {
// if nothing to hydrate
if (!ref.myButton) return
const doSomething = e => console.log(e.target, 'was clicked')
ref.myButton.map(button => {
button.addEventListener('click', doSomething, { signal })
})
}
export default component
Cleanup
If the component returns a function, or an array of functions, this will be called on page shift. Good when the component need to do something after it's unmounted.
ts
// /frontend/components/my-component.ts
import { Component } from '~/types'
const component: Component = ref => {
if (!ref.myElement) return
const doSomething = () => console.log(e.target, 'was clicked')
return ref.myElement.map(element => {
const interval = setInterval(doSomething, 1000)
return () => {
clearInterval(interval)
}
})
}
export default component
ts
// /frontend/components/my-component.ts
import { Component } from '~/types'
const component: Component = ref => {
if (!ref.myElement) return
const doSomething = () => console.log(e.target, 'was clicked')
const interval = setInterval(doSomething, 1000)
return () => clearInterval(interval)
}
export default component
Flexibility
A component can be as small as:
ts
const smallComponent: Component = ref => {
if (!ref.myElement) return
console.log(ref.myElement)
}
or even:
ts
const smallerComponent: Component = ref => console.log(ref)
or why not:
ts
const smComp: Component = () => console.log('hllo wrld!')
even:
ts
const c: Component = console.log