React. Convert from library to a framework

Rajesh Naroth
5 min readSep 9, 2019

It is only a short time during a discussion of Angular vs Vue vs React that someone would make the statement..

React is a library not a framework.

Not true. React is a framework that provides you with many features such as:

  • state management (useState, useReducer, useContext, props)
  • code-splitting and lazy loading(lazy, Suspense)
  • A clean component design model
  • css-in-js
  • templating (JSX)
  • portals
  • optimization functions (memo)
  • error boundaries

Unlike frameworks such as Angular and Ember, React is not opinionated. It doesn’t enforce a set of conventions. This is good and bad. More good than bad. In the hands of a “lesser” programmer, what ever that is, you may create a less than ideal app. However, if you follow best practices around, React can allow you to develop a very easy to reason web application with a linear scaling complexity.

Because React by itself doesn’t try to solve many of the concerns, multiple open source libraries are available to solve the same issue. react-intl vs react-i18next, react-router vs reach-router. Formik vs redux forms. Eventually the simplest, most light weight one with the best DX wins.

In this article, I will attempt to solidify the React framework a bit with some opinionated library choices.

Create React App aka CRA

npx create-react-app new-app --typescript

create-react-app is an actively maintained utility evolving with developer needs. In most cases, that is all you need. If you ever need to eject, do NOT use it. Get the latest stable one and upgrade as you go. Some of the items mentioned below are already setup for you when you use CRA.

TypeScript

I am not advocating the use of TypeScript. But when used in moderation, it can help. If you’re spending a lot of time solving typing issues, looking up on the web on how to type this and that, you need to reevaluate your approach. Typing in itself should never be the focus. Your focus is better spend on your business logic and tests. When I use TypeScript, my only goal is Communication. Prop Types are fine candidates for typing. I type my redux actions and reducers. Any general purpose re-used code can benefit from static typing. Always be wary of the syntax noise that TypeScript introduces.

Styling

CSS

CSS is a lovely monster in the global space that will grow tentacles over time and make spaghetti out of your code. You need to be prepared to tame this one. The first weapon for that is SASS.

npm i node-sass

This allows you to write sass instead of css. Always recommended.

CSS in JS

CSS in JS exists for mainly two reasons. You won’t pollute the global space and you can delete your code without worries. For those who worry about writing css in javascript, css modules allow you to create a separate css/sass files.

State Management

Redux is the best state management library out there. With new hooks support, it becomes fairly easy to master it.

npm i redux react-redux

In simple cases all you will need is async/await to handle async actions. But sometimes, you may need to do certain checks before performing an action. redux-thunk is a simple middleware that can dispatch action objects or action creator functions.

You can also look at redux-saga, a library with a high learning curve. Its API is also not small. One of the biggest benefit of saga is that you can cancel multiple async actions and just execute the latest one.

“Everything in Redux” may not be a good approach. With useContext and useReducer hooks, you can isolate state within their own container components. This also makes it easy to delete code.

Routing

You can choose react-router or reach router. Both are nice but I pick react-router because it is more prevalent and the difference between them are minimal.

npm i react-router-dom

I18n

npm i i18next

Keeping your app translation ready will avoid a huge headache later. i18next has a clean API.

A component library.

This will be one of the most important choices that you will make early on. There are several choices and do your homework. When in a pinch I’ve leaned on Reactstrap. If you have the luxury, create your own and maintain it in its own repo.

npm i bootstrap reactstrap

Storybook

Whether you develop your own components or not, Storybook (or Styleguidist) is an essential component for UI apps. It allows you to share components, recipes and guidelines. IMHO it is one of the best documenting tool for UI

Forms

An often ignored topic in React tutorial. Formik is a great choice. With the validation utility Yup, they form a great combo. Simple to adapt, easy to learn

npm i formik yup

XHR Calls

Axios has a very clean API. I highly recommend it for use with REST or GraphQL.

npm i axios

Pick a utility library

You can use ramda.js or lodash/fp. These libraries will arm you with a good set of utility functions. For instance, seen this pattern?

const zip = contact && contact.address && contact.address.zipcode

You can use lodash’s pick function.

const zip = pick(contact, ['address', 'zipcode'])

or you can wait until optional chaining is available. The point is using one of these libraries can speed up development.

Testing

CRA ships with jest. For UI development you can use enzyme or react-testing-library. There are several schools of thought when it comes to UI testing. Chart your own path but unit testing is elemental and the easiest to complete.

Kent Dodds says Write tests. Not too many. Mostly integration

Eric Elliot says Mocking is a Code Smell

Martinfowler.com says Unit Testing is your foundation

Linting

Arm your code with a linter such as tslint. Use an opinionated style guide such as airbnb javascript guide. Use a formatter like Prettier and set your VSCode to format on save. No more bickering over styling nits. Just deal with it.

npm i -D tslint tslint-config-prettier tslint-react

Pre-commit hooks

Follow this article. It is very very simple with husky.

Code organization

CRA gives you a start. But you will need to engineer it a bit more. Dan Abramov says something like this. He is probably right but junior developers need a convention and the sooner you have one, the better.

So here is one you can follow: https://jaysoo.ca/2016/12/12/additional-guidelines-for-project-structure/

My projects have evolved to look something like this:

src/
index.ts
assets/
images/
css/
bootstrap/
__tests__/
withAuthentication.ts
withI18n.ts
withRedux.ts
withRouter.ts
withAuth.ts
withStrictMode.ts
withErrorBoundary.ts
index.ts
components/ // common components
__tests__/
Image.tsx
Title.tsx
index.tsx
helpers/
__tests__/
index.ts
xform.ts
app/
App.tsx
AppShell.tsx
Navigation.tsx
App.scss
features/
homepage/
__tests__/ // unit and integration
components/ // Containers and presentation
HomePage.tsx
HomePageContainer.tsx
HomePage.scss
state/
actions.tsx
reducer.tsx
context.js
index.tsx
dashboard/
__tests__/
components/
Dashboard.tsx
DashboardContainer.tsx
state/ // local state
actions.tsx
reducer.tsx
context.js
index.tsx
services/ // API calls
__tests__/
auth.ts
rbac.ts
index.ts
types/

Tests are embedded within their own folders. Features have their own “pods”. index.js will export everything needed from a pod. Deep nesting should be avoided. Make it easy to delete features.

There are many ways to skin a cat. A little bit of planning can help you develop a maintainable app that will live a long time.

--

--