What a hook is
Functions whose name starts with use: what they give a component, and the two rules for calling them.
You already know functions. A component is a function that returns what should appear on the page. A hook is a function a component calls to *get* something: a value to remember between clicks, the store's data, a price formatter.
Hooks are easy to spot: their name starts with use. You call them at the top of your component, never inside an if or a loop, so React can match each call to the same slot every time the component runs.
First, a hook from React itself
useState gives a component a value it remembers, and a function to change it. Changing it makes React run the component function again, which is how the screen updates.
import { useState } from 'react';
export function Counter() {
const [count, setCount] = useState(0); // a hook: always at the top
return <button onClick={() => setCount(count + 1)}>Clicked {count} times</button>;
}
Now a hook from the engine
The engine's hooks work the same way. useTheme() hands your component the merchant's theme choices: colors, font, settings. Below, it runs against the real demo store.
#ed1c24#000000#6e0000font: Dubai · isRTL: false
settings: {…} 26 keys
import { useTheme } from '@salla.sa/twilight-theme-engine/hooks/useTheme';
export function PrimaryButton({ children }: { children: React.ReactNode }) {
const { color } = useTheme();
return (
<button style={{ background: color.primary, color: color.reverse_primary }}>
{children}
</button>
);
}
The two rules
- Call hooks only at the top level of a component (or of another hook), never inside conditions, loops or event handlers.
- Call them only from components or other hooks, not from plain functions.
Break a rule and React either throws or mixes up which value belongs to which call. The ESLint plugin eslint-plugin-react-hooks checks both rules as you type.
Your own hooks
A function of your own whose name starts with use and that calls other hooks is a hook too. It is how you package a piece of behaviour to reuse: the lesson Putting it together writes useCartSubtotal(), which follows the cart total through the Salla SDK.
import { useStore } from '@salla.sa/twilight-theme-engine/hooks/useStore';
import { useTranslation } from '@salla.sa/twilight-theme-engine/i18n';
// A custom hook: a name starting with "use", built from other hooks.
export function useStoreGreeting() {
const { name } = useStore();
const { isRTL } = useTranslation();
return isRTL ? `أهلًا بك في ${name}` : `Welcome to ${name}`;
}
In engine terms
- Most engine hooks have their own import path, such as
@salla.sa/twilight-theme-engine/hooks/useStoreor/hooks/useMoney.useIsClient,useDateanduseNumberexist only in the/hooksbarrel;useTranslationcomes from/i18nanduseTwilightfrom the package root. - React matches hook calls to their stored values by call order, which is why the order must be the same on every render.
react-hooks/rules-of-hooksreports a conditional call as an error. This repository's root ESLint config turns it on; the engine'stwilightEslintConfig(/eslint) does not include it, so addeslint-plugin-react-hooksto your theme's own config. - Most engine hooks read
TwilightProvider's context, anduseTwilight()throws outside it, so use them in components rendered inside the provider: in a theme, that is every page.
Next, see every engine hook in the Hooks reference, or continue the track.