4 things to do after Create-React-App

4 things to do after Create-React-App

And rating how necessary I think they are

Featured on Hashnode

You are starting a new front-end application and you've chosen React. Great! What next? Here is a list of things that I do after I create a new React application. There may be more that you choose to do, or maybe less. This is just what I choose to do.

1. Absolute pathing

This is a simple one, but I do it so that I can import modules from the root of my project. Add this to jsconfig.json file at the root of your project:

{  
  "compilerOptions": { 
    "baseUrl": "src",
    ...
  }, 
  "include": ["src"]
  ...
}

Instead of importing stuff like import Component from '../../../components/component' you can just import from the src directory. So it becomes import Component from 'components/component'.

10/10 - should come standard in CRA.

2. Setting up my "root context"

I use context most of the time for saving state, this is just a personal choice of mine. When projects start getting larger, it may make sense to move to some other state-management tool, but starting out I think this is fine.

I create a directory called contexts and I create an index file that looks something like this:

import React from 'react'
import { DarkModeProvider } from './dark'

const RootProvider = ({ children }) => 
  <DarkModeProvider>
    {children}
  </DarkModeProvider>

export default RootProvider

An example Dark Mode provider might look something like this (you import the DarkModeProvider in the root context, and import the default export in the component you are consuming that context in):

import React, { createContext, useMemo, useState } from 'react'

const Context = createContext()

const DarkModeProvider = ({ children }) => {
  const [darkMode, setDarkMode] = useState(false)

  const value = useMemo(() => ({
    darkMode,
    setDarkMode,
    toggle:  () => setDarkMode(prev => !prev),
  }), [darkMode, setDarkMode])

  return <Context.Provider value={value}>{children}</Context.Provider>
}

export { DarkModeProvider } 
export default Context

Then inside of your main App.js, import the RootContext and wrap your entire app in the RootContext. This is how I provide things that should be everywhere like Auth, Dark Mode, some application state, other singletons, etc...

With the help of our first tip, we can consume the dark mode context by importing like this: import darkModeContext from 'contexts/dark-mode'

9/10 - Worth doing in almost every app.

3. Set up routing

I use react-router-dom in all of my projects personally. I like it. There isn't a lot to add here besides what their documentation specifies. Something to note is that I usually add the routing inside the RootContext. One thing you can do is add a component that consumes some sort of AuthContext that extends react-router-doms Route component. This means that instead of checking if a user is logged in on every page separately, you can just use AuthedRoute to redirect if they aren't logged in. Might look something like this:

import React, { useContext } from 'react'
import authContext from 'contexts/auth'
import { Route, Redirect } from 'react-router-dom'


const AuthedRoute = ({ children, ...props }) => {
  const { user } = useContext(authContext)

  return !user ? <Redirect to="/login" /> : <Route {...props}>
    {children}
  </Route>
}

export default AuthedRoute

Note this specific example is just an idea, depending on how you do auth, yours may look different.

7/10 - maybe not necessary for all apps, but I like it.

4. Styling and app components

This is probably the most in-flux area for react apps these days. There are new CSS solutions being introduced and debated every week. Lately, I have favored Tailwindcss, but there are plenty of options here, and many of them are great. Emotion, Antd, Bulma, plain CSS modules all are great candidates. What I do on top of this, is create a components directory where I can create buttons, input boxes, and any other elements that I want to reuse in multiple places in my app with functionality and styling baked-in.

Paired with the first tip, we can import components like import Button from 'components/button which is the bees knees.

Here is an unstyled version of a button that adds a loading indicator to the button when the passed onClick function returns a promise. Until the promise is resolved, the button will show the loading indicator, and will not repeat the action if clicked. No more adding loading state everywhere you need a button to indicate a loading state. It is now baked in! (make sure the onClick returns the promise...)

import React, { useState } from 'react'
import Loader from 'components/loader'

const Button = ({ children, onClick, disabled, ...props }) => {
  const [loading, setLoading] = useState(false)
  return <button
      type="button"
      disabled={disabled || loading}
      onClick={(e) => {
        if (!loading) {
          const val = onClick(e)
          const isPromise = val instanceof Promise
          if (isPromise) {
            setLoading(true)

            return val.then((res) => {
              setLoading(false)
              return res
            })
          }
          return val
        }
        return null
      }}
      {...props}>
      {children}

      {loading ? (
        <LoaderWrapper>
          <Loader height={18} width={18} />
        </LoaderWrapper>
      ) : null}
    </button>
}

export default Button

9/10 - must have.

Button component: 8/10 - please steal this.

Conclusion

These are just a few of the things that I like to do for new apps in general. Again, depending on specific use cases, there may be more that you do or don't do, but these are things that I have found I do with almost every new app I start.

That's a wrap ladies and gentlemen. Let me know what you liked! Let me know what you would add? Happy to answer questions!

Photo by Akil Mazumder from Pexels