DEV Community

Cover image for My barebones React component snippet
Andreas Riedmüller
Andreas Riedmüller

Posted on

My barebones React component snippet

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
Enter fullscreen mode Exit fullscreen mode

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

Import React

import React from 'react'
Enter fullscreen mode Exit fullscreen mode

This is needed to be able to write jsx.

concatClassNames

import { concatClassNames as cn } from '../../helpers.js'
Enter fullscreen mode Exit fullscreen mode

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.

styles.module.css

import * as styles from './styles.module.css'
Enter fullscreen mode Exit fullscreen mode

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 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

Named export for the component

export function FancyBox(props) {
Enter fullscreen mode Exit fullscreen mode

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:

import { List, ListItem } from '../components/List'
Enter fullscreen mode Exit fullscreen mode

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

  const {
    className,
    children,
    ...containerProps
  } = props;
Enter fullscreen mode Exit fullscreen mode

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:

<FancyBox onClick={handleClick} id={'this-is-unique'} />
Enter fullscreen mode Exit fullscreen mode

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

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

  return <div className={cn(className, styles.fancyBox)} {...containerProps}>
    {children}
  </div>;
Enter fullscreen mode Exit fullscreen mode

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 for a button and so on.

The complete snippet

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>;
}
Enter fullscreen mode Exit fullscreen mode

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

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>;
}
Enter fullscreen mode Exit fullscreen mode

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

Top comments (0)