Skeleton and Architecture for my React App Template

Picking up from the last post, I will be talking about the higher-level architecture of how I structure my React Applications. I package everything into one neat NPM package which you can use as a template with CRA.

Skeleton and Architecture for my React App Template

Picking up from the last post, I will be talking about the higher-level architecture of how I structure my React Applications. I package everything into one neat NPM package which you can use as a template with CRA. Just type run the command npx create-react-app my-app --template cra-template-xz.

This is the second post in the series, check out the first post here ๐Ÿ‘‡

How do I structure my React Application - Motivation
Every time I sit down and make a Web Application with React, I find myself constantly going through the same motion. Running the same scripts, using the same components to build the skeleton. So, I made a CRA template and you can use it too.
Why did I make a CRA template?

The Architectural Problem and Solution

We learn about Props Passing within the first 15 minutes of doing any React quick start guide. Its simplicity allows us to craft complex components with composition, but it is difficult to create elegant applications with that communication model solely. To allow distant components to communicate with each other, we often use a global state like the Context API or Redux. This eliminates the inelegant solution of storing state all the way at the root of the component hierarchy tree and propagate it down to the individual components at the leaf of the tree. This approach also allows individual components to read/write to the shared global state with the Flux model.

Now, there are some apparent shortcomings with this approach despite its merits. Each component's state is now kinda bound to the global state. Potentially, we might have to normalize the desired piece of state at each component before consuming it. Since all data is fetched internally within the individual components, I find it harder to visualize where the data is coming from, its structure and potentially causing it to be more difficult when debugging.

I smashed both approaches together to overcome the shortcomings of both solutions, splitting the components into 2 ideological categories, Page Components and UI Components.

Pages will act as templates. I can set the router to access these pages. I can set standardize things like the document title (the browser tab name). I can apply styles. I can change the page header in the document with just a prop. But most importantly, I can conduct all global state-related logic in my Page Components. I can access the global state, normalize the data before prop passing it down to my UI Components, I have one standardize place to dispatch global state actions.

UI Components act as self-contained React components. You can think of them as widgets or typical React components. They accept data through props and modify application data through state lifting onto its parent Page Component.

Look at Graph ๐Ÿ“ˆ

That's a pewdiepie reference incase you didn't get it. Anyways~

These are the 2 approaches, props passing and using global state on individual components.

And this is the communication model of the solution I adopted.

Prop passing to Page Components and then Flux from there onwards.

This abstraction retains the ability to write complex composition components while reducing the complexity of having to consider the global state at every single individual component.

However, this is not the perfect solution. It is great for small or medium size applications where the component tree is pretty shallow. For larger applications with a deep component hierarchy, we will (once again) run into the problem of props passing through too many layers. Since I am a student and I routinely work with applications that are not too huge in my personal time and with school work, this architecture works perfectly fine for me (at the moment).

This is the truncated folder structure.

my-app
โ”œโ”€โ”€โ”€public
โ””โ”€โ”€โ”€src
    โ”‚   index.tsx
    โ”œโ”€โ”€โ”€App
    โ”‚       App.tsx
    โ”‚       tabConfig.tsx
    โ”œโ”€โ”€โ”€components
    โ”‚   โ”‚   index.tsx
    โ”‚   โ”œโ”€โ”€โ”€Counter
    โ”‚   โ”‚       Counter.less
    โ”‚   โ”‚       Counter.tsx
    โ”‚   โ”œโ”€โ”€โ”€Layout
    โ”‚   โ”‚       Layout.less
    โ”‚   โ”‚       Layout.tsx
    โ”‚   โ””โ”€โ”€โ”€MySubMenu
    โ”‚           MySubMenu.tsx
    โ”œโ”€โ”€โ”€pages
    โ”‚   โ”‚   index.tsx
    โ”‚   โ”‚   Template.less
    โ”‚   โ”‚   Template.tsx
    โ”‚   โ”œโ”€โ”€โ”€CounterDemoPage
    โ”‚   โ”‚       CounterDemoPage.tsx
    โ”‚   โ””โ”€โ”€โ”€DemoPage
    โ”‚           DemoPage.tsx
    โ””โ”€โ”€โ”€redux
The folder structure

Fin

In the next post, I will go into specifics about the implementation of this architecture. I will probably also talk about how I implemented many parts of my CRA template, what quality-of-life features I have added to it and stuff.

If you want to try out the template today, you can run npx create-react-app my-app --template cra-template-xz or visit the npmjs page:

cra-template-xz
*This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).*