My barebones React component snippet
Tags: react, phpstorm, javascript
Published: 2022-07-29 16:31:10

---
title: My barebones React component snippet
published: true
description: And a ready-made opinionated snippet that helps creating a new components.
tags: react, phpstorm, javascript
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/090tg5rba4gnhgdpd2i3.png
---

Having a snippet ready to start a new component is something I strongly recommend. Splitting up your project into smaller components will make your code more easy to read and maintain. Having a ready-made snippet will help you with this by making it easier to start a new component.

My workflow for creating a new component is:
1. Create new directory with an index.js file
2. Expand snippet in index.js
3. Create styles.module.css file

**Tip:** In PHPStorm you can enter a path eg. 'FancyBox/index.js' in the New file dialog and it creates both the folder and file.

```
📦 Project root
 ┗ 📂src
   ┗ 📂components
     ┗ 📂FancyBox
       ┣ 📜index.js
       ┗ 📜styles.module.css
```

My snippet contains the following code for a minimal React component:

## Import React
```javascript
import React from 'react'
```
This is needed to be able to write jsx.

## concatClassNames
```javascript
import { concatClassNames as cn } from '../../helpers.js'
```
This is especially useful when conditional classes are added to the component so I always import  it. You can find out more about this [here](https://dev.to/receter/concat-class-names-4kb1).

## styles.module.css
```javascript
import * as styles from './styles.module.css'
```
I use CSS modules in all my projects and most of my components have styles. 

I stopped using `import styles from './styles.module.css'` because Gatsby made importing CSS modules as ES modules their default.

The only donwside is that this does not yet work with react-scripts@5 as there seems to be an [issue](https://github.com/facebook/create-react-app/issues/12096) with that (it does work with react-scripts@4 though and there are workarounds for v5).

If you have an idea how to publish a component so it can be used by both a project loading CSS modules as ES modules and CommonJS you can [help me here](https://stackoverflow.com/questions/71294870/how-to-publish-a-react-component-with-css-modules-that-can-be-consumed-by-both)

## Named export for the component
```javascript
export function FancyBox(props) {
```
Making a named export for the component has some advantages over a default export. For example you can export sub components like a list item from the same location. My main component is always named exactly like the component folder.

Togehter with naming the main component file `index.js` it looks awesome when importing:

```javascript
import { List, ListItem } from '../components/List'
```
_There is a small caveat to naming all your component files "index.js": The filename says nothing about the component. So when you have the file open in your editor the tab might say 'index.js' which is a little ambiguous. For me it’s not a big problem because my Editor adds the name of the Folder when two open files have the same filename._

## Destructure props
```javascript
  const {
    className,
    children,
    ...containerProps
  } = props;
```
The first thing I do in the actual component is to destrucure the props. `containerProps` will contain ALL remaining props that are not explicitly destrucutred above this line. So if you use this component like so:
```javascript
<FancyBox onClick={handleClick} id={'this-is-unique'} />
```
The rendered div will have a click handler and an html id. This is super useful as you can use your react component like a html element without any more code. Personally I am in love with this method, but you need to be aware of the risks.

Using the spread syntax for props makes it easy to pass invalid HTML attributes to the DOM or unwanted props to other components. [React Docs](https://reactjs.org/docs/jsx-in-depth.html#spread-attributes)

One rule that helps preventing this is to never use `props.something` in your component code but always add the prop you are going to use to the destructure list

At least for me it brought me more joy and comfort than trouble.

For some components I opt out of this.

## The default JSX
```javascript
  return <div className={cn(className, styles.fancyBox)} {...containerProps}>
    {children}
  </div>;
```
First the className from props gets concatenated with the className from the CSS modules stylesheet. Then the containerProps get applied and last the children prop ist passed to the div explicitly.

Of course I change the html element to whatever suits my component best, like a <button> for a button and so on.

## The complete snippet
```javascript
import React from 'react'
import { concatClassNames as cn } from '../../helpers.js'
import * as styles from './styles.module.css'

export function FancyBox(props) {

  const {
    className,
    children,
    ...containerProps
  } = props;

  return <div className={cn(className, styles.fancyBox)} {...containerProps}>
    {children}
  </div>;
}
```

## Some tips for Jetbrains IDEs like PHPStorm
In Jetbrains IDEs it is possible to read the name of the folder and use it when naming class and function name. This makes it possible to get a snippet that automatically applies the correct names.

My variables in the Live Template are:

**NAMEPASCAL**
Expression: _empty_
Default value: `groovyScript("String[] p=_editor.getVirtualFile().getPath().split('/');String prevLast = p[p.length-2];")`
Skip if defined: false

**NAMECAMEL**
Expression: _empty_
Default value: `camelCase(NAMEPASCAL)`
Skip if defined: true

```javascript
import React from 'react'
import { concatClassNames as cn } from '../../helpers.js'
import * as styles from './styles.module.css'

export function $NAMEPASCAL$(props) {

  const {
    className,
    children,
    ...containerProps
  } = props;

  return <div className={cn(className, styles.$NAMECAMEL$)} {...containerProps}>
    {children}
    $END$
  </div>;
}
```

What helps you to start new components? Let me know what you think.