While you are trying to develop a Single Page Application with React, chances are more that your codebase can get unorganized. Such an app becomes hard to debug, and when it comes to extending or updating the codebase, things get even harder.
React ecosystem comes with several excellent libraries that can be used to take care of different aspects of the app. Here in this post, we will be discussing the same.
Apart from that, in this post, we will also be discussing some good practices which need to be followed when you are upon a large scale project based on React. It is essential that everything needs to be planned based on the scalability of the project in mind. Here everything needs to be planned ahead on time.
Planning the Phase
Many a time, developers skip this step as this step is not involved in coding directly; however, it is quite important.
Why Carry out the Application Planning Phase?
While carrying out project development, one needs to manage different moving parts. The development part includes several roadblocks and yes uncertainties and so all you want is to ensure the project schedule does not get extended.
You can save yourself from this trouble through the planning phase. In this phase, you will list down every single detail, which is related to your app. Make sure that it is only possible for the development team to predict the time it would take to build single small modules of an application rather than anticipating the whole application development in a single picture.
The large project consists of multiple developers and if yours is one, then this article will help you make communication and collaboration easier with them. It is even possible for you to choose things from this article and use it for your developers to make things smoother for everyone.
Moreover, using this article, the developers can have a constant idea of their project progress. This will seem to be easier for them, especially when they are moving from one part of the project to another with time.
Step 1: Dealing with Design, UI/UX Thing
It is essential that each view in the app should be determined correctly in terms of its look and functionality. The best way to get it done is by coming up with the view of the app drawn on a paper or using some mock-up tool. Such an attempt will help you know what all elements and information you were planning to be placed on each page.
The mock-up should involve placing the app pages in the proper readable manner. There should be parent and child containers within the app. The parent containers will form the different pages of the app and all the other elements will be placed within the component folder of the application. Once the mock-up is completed, you can name each page and the components in there.
Step 2: Managing the Events and Actions in the App
Once you have decided the components to be present in the app, then it is time for you to decide which of the actions should be performed by those components in there. Later these components will dispatch those actions from within.
Step 3: Maintaining the Data in Efficient Way
There is some data associated with every component present within the app. Now, if the same data is used up by different components present within the application, then it will be considered as part of the centralized state tree. Redux will be managing that state tree.
As the same data is shared between different components within the app, any changes made to it at one place will reflect the change in the value throughout the other components.
You should list out such kind of data present in your app as they will form the model for the app and based on the value, the app’s reducers can be created by you.
Once the plan of action has been developed, now it is time you take a look at some important information that can be used for data layer setup in the app.
Go For Long Term Strategy – Think about Datasource, API, and Actions
As the size of the app grows, the Redux store will have an improper directory structure and more number of repetitive methods. This situation will make it hard to update or maintain it.
You can rearrange a few things and will be able to keep the Redux store code clean. By making the modules reusable from the beginning itself, it will become possible to save a lot of trouble later.
Design patterns in Datasource
The parts mentioned in here are used by Redux actions directly to change the state. You can set the datastore in one of the two ways mentioned below, depending upon the size of the app.
- With courier
- Without courier
When it comes to maintaining or updating the app in the long run, this approach seems to be easier. In this approach, your codebase remains clean and you no more have to make duplicate calls through axios.
However, at the initial stage, it takes time to set up everything. Again, you will enjoy less amount of flexibility.
When you arrange your datastore in this way, you will get to define POST, GET, and PUT requests for each model in a separate manner. Here the actions that will call methods for different datastore are dispatched individually through each component.
No doubt, this approach saves time. It even lets you make the needed modifications in the app without having to consider the side effects. However, it will be time-consuming to perform bulk updates and it will come with much of repetitive code.
Designing API with respect to Client Apps
When you are setting up the datastore, the layout of your store gets affected a lot from the API, based on the format in which the data is received. Many a time, it is important that you format the data before you pass it on to the reducers.
There is a lot of debate going on regarding the API designing like what should be done and whatnot. How you will be designing your API gets further affected by the size of the app and the backend framework. Just like you will be handling the backend app, keep the utility functions like mappers and formatters in a different folder.
Now you can go a step ahead. Now map the data which has some validation keys and has the structure specific to your frontend to a predefined object.
In-app actions and API calls
The usage of predefined actions is one thing that stands out when you are working with Redux. It makes changes in the data more predictable throughout the app. Defining a number of constants in the app may seem to be a long day job, but the step 2 explained in the above section makes things easier.
Using Redux with React
You can extend the functionality of Redux to systematically take care of more complex actions taking place in the app. When implementing Redux, you need to be very careful as if you fail to implement it in the proper manner, then the whole pattern of your store will get disturbed.
Planning each and every model in the large application is not possible always. Moreover, when you will make use of reducer injections in your app as it grows, you will be able to save a lot of human effort. This technique also helps the developer to get in new reducers without having to rewire the complete store.
You can even find libraries out there, which can let you get such things done quickly, but this approach will help you integrate the old code with much flexibility and less rewiring. Today the development community is using this form of code splitting actively.
Managing the Issues in the app
Let us consider a scenario. You have been working on an application which deals with real-estate. Here you demand to come up with a solution that is better and fresh from the last one.
Now the design for each and every page for it has been given on to you, you have REST API in place and you have come up with a plan of your own; still, issues can come up.
Now the CMS solution that the company has been using is quite familiar for them and they have been using it for a long time. They plan to keep the CMS the same and don’t want to go through the trouble of moving all the old blogs to a new one.
The good thing here is that the CMS comes with a readable API which offers you content for the blog. In case you have used a courier to write it, the CMS API will be on another server, which comes with different rules.
Such kind of issue comes with an app when you are trying to fetch the blog using a new API. You can use React Sagas to handle such issues.
Redux and Routing
When it comes to handling routing in the app, several tools are available out there for the people. Here in this part of the blog, we will be discussing about
react-router dom and to work with Redux, extend its functionality.
The majority of the time, react-router is used to wrap the root component along with the
BrowserRouter tag and within the
withRouter() method wrap the child containers and export them.
In this manner, the child component gets some methods which can be used for control navigation and a history prop along with some properties that remain specific to the session of the user.
As there is no central view of the history object, you can find issues when implementing it in large apps. Moreover, it is not possible to access the components which are not rendered through the route component in this manner:
In order to get over with this issue, we use a connected react router library via dispatch methods to help you use routing.
Once the initial setup is over, you can use it using Redux. You can use dispatching actions for in-app navigation. Now you can easily map the dispatch method to the store to use the connected react router within the component by following your router needs.
Dynamic UI as solution
Sometimes, even by having core SPA logic and enough backend, some of the user interface elements tend to harm the user experience for the visitors during their overall journey.
This happens because the components on the UI are not implemented properly and it is definitely an essential thing to do first. As the app scales implementing certain components or widgets may seem to be difficult and here in this part we will see how we can simplify it.
It is commonly possible to have repeated patterns happening when you are working with a great frontend app and this can happen even when you may not have started it on purpose. Every time you will be doing this, you will feel that it is repeating.
In case a constant design pattern is followed by your API, then the only thing you need to do is to pass the props like URL and the items on the page to the adaptive pagination component.
Suspense and soft loading
In the normal scenario, the network layer is said to be fault-prone and not reliable. Even though your single-page applications goes under a number of quality checks still there will be something left out, which can be things like response times, connectivity, etc. which are not under the control of the developers.
The best thing is that in spite of that not being something under their control, software developers have come up with amazing solutions that can tackle such issues.
When you are carrying out front-end development, you may want to display some lighter image to the user if yours takes time to load as you don’t want the users to see a sign of broken image.
You can do that simply using React suspense. So while the content is being loaded, you can display some spinner out there. However, you can do this manually, too, just by using
isLoaded prop in the code to true but, when you use suspense, it is much of better.
Compared to the task of managing an
isLoaded object in its global state, it is much easier to add suspense to the components. This can be done by starting with the effort of wrapping the parent App container along with React
StrictMode. You just need to be sure you are not using any deprecated React modules.
The components which are present within the
ReactSuspense tags load the component that is in the fallback prop specifically while loading the main content. Here, you need to be sure that the component which is in the fallback prop is lightweight.
The React ecosystem has revolutionized over the years and for developers, they hardly had to face any time where they had to build something again during the development. No doubt, this seems to be useful for the developers, but then it confuses them too when it comes to choosing the best solution for the project.
In terms of functionality and scalability, every project is different. So there is no single generalized approach that can be taken by you. So, before you start coding for your project, plan well in advance.
So while you will be planning out your project, you will also be able to choose the right tools as well as avoid the ones which can harm you.
Last but not the least, it is true that for any app, data plays the key role and things are not much different with React applications. This means that as your app grows, you will start collecting massive amounts of data. So before you start your project, you should also think about reducers’ actions, datastores, sagas, etc.