Introduction

React is an amazing library for building user interfaces. In combination with Next.js, it’s a powerful tool used to realize highly interactive web applications. However, it can be challenging to find the right approach for structuring components, especially in the beginning. ROQ One Frontend introduces an architecture approach that worked very well for us and many other projects in the past. Feel free to follow or modify to your unique needs.

Overview

When you look into the directory structure of ROQ One Frontend, you’ll see lots of component types, like pages, views, and partials. The following image offers a high-level overview of the structure:

Component structure

Pages

frontend/src/pages

Pages are a basic feature of Next.js:

Each page is associated with a route based on its file name.

Example: If you create pages/about.js that exports a React component like below, it will be accessible at /about.

📖 Pages | Next.js

The code placed inside a page component cannot be reused on other pages. That’s why the actual code is placed in another type of component called a view. The page itself only wires up the view and passes props like the current locale and necessary translations.

Example

🛠 pages/example/books/index.tsx

export const getStaticProps: GetStaticProps = async ({ locale }) => ({
  props: {
    ...(await serverSideTranslations(locale, ['common'])),
  },
});

export default withLocale(BooksView);
TSX

Views and partials

/frontend/src/views

The purpose of the views is to decouple React components from Next.js. This allows them to be portable and reusable across pages.

Example

🛠 views/books/books.view.tsx

export const BooksView = withAuth()((): React.ReactElement => {
  const { t } = useTranslation();
  const breadcrumbs = useExampleBreadcrumbs({ skipLast: 1 });

  return (
    <MainLayout 
       title={t('title_example')} 
       breadcrumbs={<Breadcrumbs items={breadcrumbs} />}>
      <BooksTablePartial />
    </MainLayout>
  );
});
TSX

The example above shows several capabilities of views (and also partials) in ROQ One Frontend

Authentication

If a page requires the user to be authenticated then you wrap the component into the withAuth() HOC like this:

export const BooksView = withAuth()((): React.ReactElement => {
TYPESCRIPT

Layout

The view is wrapping its TSX content into the a layout component.

return (
    <MainLayout
TSX

ROQ One Frontend ships with two layouts:

  • frontend/src/layouts/auth/auth.layout.tsx

  • frontend/src/layouts/main/main.layout.tsx

Translations

We recommend to not hard-code any text into your React components. Instead you should use the t() function which is provided by the useTranslation() hook. See Translations for more details.

Partials

To optimize the readability and reusability of components, we encourage users to avoid big views and decompose the TSX into sub-components (partials). Partials represent small pieces of the user-interface. They are mostly non-functional and provide their own styles.

A partial can belong to a view. In this case, it is placed into a sub-folder of the view. There are also partials that are intended to be shared among views. These are placed into the src/modules folder.

HOCs and hooks

React introduces two concepts to add logic to components in a clean way:

High-Order Components (HOCs)

HOCs are wrapping entire React components. This way the component can be equipped with cross-functional logic like authentication. ROQ One Frontend ships with HOCs like withLocale() and withAuth()

📖 Higher-Order Components – React

Hooks

Hooks contain the logic of views and partials by using callbacks and can be placed into the directory of a view. If you want to share a hook between views, you can put it to modules. ROQ One Frontend uses hooks like useTranslation() and useExampleBreadcrumbs().

When you do a GraphQL request to either ROQ One Backend or ROQ Platform then you usually implement them here, see GraphQL-client (frontend)

📖 Introducing Hooks – React

State management

ROQ One Frontend uses Redux for state management. This is only used when it adds clear and significant benefits, not for trivial cases when props can simply be passed from one component to another. To avoid verbosity, Redux is not implemented directly. Instead ROQ One Frontend uses the Redux Toolkit for simplicity. The implementation follows toolkit’s official documentation, meaning you’ll find actions, selectors, and slices in ROQ One’s views and modules.

📖 Getting Started | Redux Toolkit