ScandiPWA components are reusable, extendable, and independent UI logic that divides the UI into smaller pieces to make them easier to manage and share across an application. The ScandiPWA theme utilizes **React class-based components** defined in the component directory, and all components may follow the same structure for consistency across the project and make it easier for different people to work together in different aspects of the project.

ScandiPWA operates following a complex architecture and has its own lifecycle. There is a set of rules in the internal structure that makes the application work and separates the raw templates from business logic, make sure you’re familiarized with it.

What is the architecture of ScandiPWA?

The most recommended way to create or install a new ScandiPWA component is via the official ScandiPWA CLI. Make sure to keep your code extensible and import declarations well-structured!

What is a class-based component?

ScandiPWA utilizes class components, which makes it easier to override methods and properties when compared to function components. This makes it a perfect combination to work with extensions and plugins.

This is a component based on ES6 class that extends React.Component or React.PureComponent class:

<aside> ➡️ ScandiPWA uses React.PureComponent over React.Component. This is done to improve performance. React.PureComponent utilizes simple props caching to avoid unnecessary re-renders.

</aside>

import { PureComponent } from 'react'

class Welcome extends PureComponent {
  render() {
		// this can access any props defined as name in the container
    return <h1>Hello, {this.props.name}</h1>;
  }
}

<aside> ➡️ Whether you declare a component, it must never modify its own props. Such functions are called “pure” because they do not attempt to change their inputs, and always return the same result for the same inputs. All React components must act like pure functions with respect to their props.

</aside>

How to create a component using ScandiPWA CLI?

Run the following command:

scandipwa create component [--container] [--redux] <name>

Where:

<aside> ➡️

When creating a component, the component name must start with an upper case letter.

</aside>

<aside> 🚨 The ScandiPWA CLI approach is the most indicated for component creation. Learn more about ScandiPWA CLI:

How to use the ScandiPWA CLI?

</aside>

What is the structure of a component?

To ensure consistency among components made by different people in a project, a defined structure of rules and directories should be established to make them work together.

<aside> ℹ️ In ScandiPWA, components are located under src/component for simple components, or src/route for components that are used as the main components in routes. Component names follow the UpperCamelCase (also known as PascalCase) pattern. For example, ProductList.

</aside>

This section explains how to structure each component file, describing the behaviour of each file, as well as their responsibilities. A component named <COMPONENT> will be defined in the directory component/<COMPONENT> containing the following files:

Common patterns, that apply to all types of files:

How to work with .component.js files?

This file is responsible only for the UI rendering implementation via JSX. The .component file shouldn't be responsible for any business logic, such as fetching or manipulating data. For better separation of concerns, move all business logic to the .container file. (However, it is allowed to maintain basic UI states e.g. to keep track of whether an accordion is open)

<aside> ℹ️ You are able to access props defined in the container through this.props.<PROPS_NAME>, for example, this.props.age , or by destructuring it like const { age } = this.props.

</aside>

Structuring it properly is key to a well-written component. There are just two rules for structuring it:

ScandiPWA uses React.PureComponent over React.Component. This is done to improve performance. React.PureComponent utilizes simple props caching to avoid unnecessary re-renders.

Here's a simplified and annotated version of component/ProductPrice/ProductPrice.component.js:

<aside> ✅ Note that this component is broken down by defining one function for each part. This is better than writing one long render method for several reasons:

Besides the use of namespaces, default export, non-default export, and import declarations structure, ScandiPWA components have these common patterns:

How to work with .container.js files?

The container must implement logic. A logic must prepare the props (data) for a component for rendering (How to create a component?). The container might listen to a Redux store (How to listen to Redux stores?).

The container file is responsible for:

How to Work with Redux?

Besides the use of namespaces, default export, non-default export, and import declarations structure, ScandiPWA containers have these common patterns:

For example:

How to work with .config.js files?

Due to Webpack optimization limitations, it is better to practice and more efficient to define constants you use in .component or .container in a separate file and import them where you need. This is what .config files are for.

You can export constants by defining them in .config file:

export const DISPLAY_PRODUCT_PRICES_IN_CATALOG_INCL_TAX = 'DISPLAY_PRODUCT_PRICES_IN_CATALOG_INCL_TAX';
export const DISPLAY_PRODUCT_PRICES_IN_CATALOG_EXCL_TAX = 'DISPLAY_PRODUCT_PRICES_IN_CATALOG_EXCL_TAX';
export const DISPLAY_PRODUCT_PRICES_IN_CATALOG_BOTH = 'DISPLAY_PRODUCT_PRICES_IN_CATALOG_BOTH';
export const IMAGE_LOADING = 0;
export const IMAGE_LOADED = 1;
export const IMAGE_NOT_FOUND = 2;
export const IMAGE_NOT_SPECIFIED = 3;

<aside> ✅ How to use these values? to use these constants just import where you need it, for example:

import {
    IMAGE_LOADING, IMAGE_LOADED, IMAGE_NOT_FOUND
} from 'component/Image/Image.config';

</aside>

How to work with .style.scss files?