How we develop frontend components
This is how we build components for the Owncast web UI. Use it when changing existing components or adding new ones. A shared pattern keeps the project readable and maintainable.
Functional componentsโ
React has two ways to write components: class-based and functional. Class-based has fallen out of favor, so we write functional components. See the React component docs.
The pattern we useโ
Statelessโ
export type MyNewButtonProps = {
label: string;
onClick: () => void;
};
export const MyNewButton: FC<MyNewButtonProps> = ({ label, onClick }) => (
<button onClick={onClick}>{label}</button>
);
Statefulโ
export type MyNewButtonProps = {
label: string;
onClick: () => void;
};
export const MyNewButton: FC<MyNewButtonProps> = ({ label, onClick }) => {
const handleClick = useCallback(() => {
alert(label);
onClick && onClick();
}, [label, onClick]);
return <button onClick={handleClick}>{label}</button>;
};
There are many common ways to write components, so settling on one keeps things consistent. For why this style, see the PR that introduced it.
Error boundariesโ
Components with substantial state and internal logic should be wrapped in an error boundary, so an unexpected error shows a fallback instead of crashing the page. Stateless view components rarely throw and don't need one. The ComponentError component is a prebuilt error state with a bug-reporting button.
import { ErrorBoundary } from 'react-error-boundary';
<ErrorBoundary
fallbackRender={({ error, resetErrorBoundary }) => (
<ComponentError
componentName="DesktopContent"
message={error.message}
retryFunction={resetErrorBoundary}
/>
)}
>
<YourComponent />
</ErrorBoundary>
Storybookโ
We use Storybook as a component library where you can see and interact with each component. Include a .stories.tsx file with every exported component, and update it when you change a component. Run the Storybook server with npm run storybook.
Linting and formattingโ
We use Prettier and ESLint for JavaScript and TypeScript. Set them up in your editor or run them manually. Linting or formatting errors will block a PR until they are fixed.