with one click
react-component-writing
// React component patterns and style guide for the Commons monorepo. Use when creating React components, working with GraphQL in components, or implementing internationalization with MessageFormat.
// React component patterns and style guide for the Commons monorepo. Use when creating React components, working with GraphQL in components, or implementing internationalization with MessageFormat.
[HINT] Download the complete skill directory including SKILL.md and all related files
| name | react-component-writing |
| description | React component patterns and style guide for the Commons monorepo. Use when creating React components, working with GraphQL in components, or implementing internationalization with MessageFormat. |
export const MyComponent = ... (no default exports)React.FCinterface MyComponentProps {
title: MessageFormat;
onSubmit: () => void;
}
export const MyComponent = ({ title, onSubmit }: MyComponentProps) => {
// ...
};
Simple structure—see example: commons-packages/frontend/shared/example-ui-component/
interface ExampleUiComponentProps {
description?: MessageFormat;
onSubmitClick: () => void;
title: MessageFormat;
}
export const ExampleUiComponent = ({ description, onSubmitClick, title }: ExampleUiComponentProps) => {
// Component implementation
};
Separate into two components:
MyComponentUI): Renders UI, receives data as propsMyComponent): Fetches data, passes to UISee example: commons-packages/frontend/shared/example-graphql-component/
// UI sub-component
interface MyComponentUIProps extends MyComponentBaseProps {
error?: ApolloError;
isLoading?: boolean;
data?: GetDataQuery['data'];
}
export const MyComponentUI = ({ error, isLoading, data }: MyComponentUIProps) => {
if (isLoading) return <Spinner />;
if (error) return <ErrorComponent error={error} />;
return (/* render UI */);
};
// GraphQL wrapper
export const MyComponent = ({ id }: MyComponentProps) => {
const { data, loading, error } = useGetDataQuery({ variables: { id } });
return (
<MyComponentUI
isLoading={loading}
error={error}
data={data?.data}
/>
);
};
use: useMyHookhooks/ directory or co-locate with componentinterface UseMyHookResult {
value: string;
setValue: (v: string) => void;
isLoading: boolean;
}
export const useMyHook = (initialValue: string): UseMyHookResult => {
// ...
};
Use MessageFormat for text. Render with useFormatMessage from Commonplace (not useIntl from react-intl):
import { Text, useFormatMessage } from '@commons/frontend/shared/commonplace';
const Component = ({ pageNumber }: { pageNumber: number }) => {
const formatMessage = useFormatMessage();
const nextText = formatMessage({ id: 'shared.next' });
return <Text text={`${nextText}: ${pageNumber}`} />;
};
import { render } from '@commons/frontend/rtlTests/test-utils';
This wraps components with necessary providers (IntlProvider, MockedProvider, AppStateProvider, Router).
Test UI sub-component directly — pass props without mocks:
render(<MyComponentUI data={mockData} isLoading={false} />);
Use GraphQL mocks — test full wrapper:
render(<MyComponent id="123" />, { customMocks: [myMock] });
See examples: commons-packages/frontend/shared/example-graphql-component/__tests__/
Co-locate related files:
my-component/
├── my-component.tsx
├── my-component.graphql
├── my-component.css (or .module.css)
└── __tests__/
└── my-component.spec.tsx