Converting Bootstrap HTML to Reactjs
React is being used by startups and small businesses all around you. Utilizing the contemporary tooling and composable architecture of React, they release new features at a rate that is unimaginable to you.
React is something you’d like to start utilizing, or maybe you’ve already started using it for some minor components.However, you simply cannot afford to rewrite your front-end from scratch! Your customers use your front-end frequently, and they anticipate updates and new functions!
Fortunately, you don’t have to rewrite—in fact, you shouldn’t! You can switch over to React in bits and pieces.
In this article, I’ll show you how to wrap your current code in a React component without compromising your application’s functionality, separate your application’s states and representation, and create the possibility for additional refactoring.
Why should we want to do that?
Risky are extensive rewrites. When you rewrite your application, you’ll have to choose between two difficult options: either you release your new version quickly, but with significantly fewer features than the one you currently have, or you wait until you’ve reached feature parity, delaying feedback on the finished product and releasing an unproven application. Additionally, the longer you wait, the longer you will keep both applications active.
It’s critical to regularly release new versions to your clients in order to get feedback so that you can safely and securely improve.
You may introduce your first React component in a secure manner right away if you adhere to the instructions provided in this article. This will enable you to quickly determine whether this is the best course of action and validate your approach. Working within an existing application has the apparent drawback that it will take some additional time before you can fully benefit from using React. But if you follow these instructions frequently, you’ll be able to get there with much less risk.
Getting started:
I’m going to presume that the HTML markup delivered from the server and the JavaScript that makes this page interactive make up your application.
The processes will be similar if you already use another framework, like Angular, although they will depend on how that framework’s API works. Such circumstances are outside the purview of this essay, but feel free to post questions in the comments section below concerning your situation.
When JavaScript is loaded, event handlers are added (either using addEventListener or a library like jQuery), and the DOM is updated when these events occur. Adding or removing CSS classes or changing the style attribute are the two most common ways to modify the DOM.
Your client code most likely calls your backend service as well, updating the current page as necessary. The migration strategy will be the same whether you are changing a few classes in the DOM or rewriting the complete page in response to an HTTP request.
The likelihood is that these DOM manipulations take place either directly or through the use of an imperative DOM manipulation package like jQuery if you’re working with an older codebase. Frequently, only direct DOM manipulation is used to express the application’s state. Due to this, it is challenging to remember the various states that an application may be in at any given time, the transitions that may occur, and the proper way to update the DOM to reflect those states.
In the worst-case scenario, the code that refreshes the DOM is scattered across numerous locations or unrelated code is splayed together, making it challenging to separate the various concerns.
There are several benefits to converting this “spaghetti code” into React components. It will first teach the concept of components, allowing you to group together relevant code and compose smaller pieces into a larger composition. Second, by doing the actions listed below, you can distinguish between the states of your application and how they are represented in the DOM. This will lessen the possibility of being inconsistent and increase modifiability.
Finally, to further increase the reliability of your application, you may make use of other React-specific features like error boundaries.
What then shall I do?
You’ll first need to choose whether React is the best option. I won’t try to persuade you here; there are already a lot of excellent resources. However, you can follow the next stages if you do decide to go toward a React application.
Be prepared:
The initial step is to prepare your tools. The remainder of this post will presume that you can transpile JavaScript with contemporary capabilities and have a build step (using a programme like webpack) (using a transpiler like babel).
To sum it up:
We want to transition to React components responsibly, thus we’ll first work to update as little code as feasible. Imagine your code is structured as follows:
A very simple example of the type of code you might see is this JavaScript implementation of an “accordion” component. The concept is that we attach event handlers and modify the DOM inside of them, obviously making your code more complex.
Introducing React is our next step. This imperative code will be contained within a new React component. You can carry out this action for a connected section of your codebase. The ideal place to start would likely be a whole file, or if your files are large, a sizable chunk of related functionality. Don’t worry; you can remove small bits afterwards and tidy up the mess.
All of our imperative code will be placed in the componentDidMount lifecycle method, which is invoked when the component has been mounted into the document, as opposed to the render method, which is where most React introductions begin. We’ll make the render method return null because it’s necessary in order to prevent React from changing the DOM.
We then render this component right away using ReactDOM.render(element, root), using an empty container for the root that isn’t attached to the document, and we get something that looks like this:
What have we accomplished thus far, then? Actually not much, as what we’ve done thus far is essentially the same as writing the code in a function and calling it right away! However, React was added, and as a result, everything continues to function. Additionally, following this step, any tests you had for this code should still pass (HINT: you really should!). If they don’t, they are probably too closely connected to the DOM, for instance because you’ve mocked the DOM tree’s functions too rigidly.
This first stage is comparable to the Strangler Pattern, as one of my coworkers noted, and he is entirely correct. Working with legacy code always employs a consistent methodology.
Describe your company:
As I’ve already indicated, because state transitions and DOM updates are combined in this outdated code, keeping track of all the states and transitions is typically the most challenging component. The two will be divided in the following phase by adding state to our component.
The active panel in each accordion and the activation and deactivation of a panel in an accordion make up the only state and transition in the Accordions component from the example. Multiple accordions may be displayed on a page thanks to the imperative code, and we want to keep this capability when we migrate.
To begin, we create the state’s shape for this particular transition. It must hold the active panel for each accordion on the page. A JavaScript Map object can be used in this situation perfectly. We’ll also need this behavior in our component because the imperative code will begin in the ‘state’ described in the DOM (i.e., the panel with class accordion-expanded is automatically active). To read the initial state from the DOM in the component’s function Object we’ll search for panels with the accordion-expanded class in each accordion and add those panels to the accordion’s entry in the map. At the conclusion of the function Object, we’ll set the map into this state.
Once the state has been read from the DOM, we must begin using it as our update mechanism. We’ll swap out the click event handler that modified the DOM for one that merely calls the setState method of the component. An updater function that is run by React with the current state and should produce a new (partial) state can be passed as the first argument to setState. This function returns an object that is combined with the current state. Anything in state should be regarded as immutable; so, we should replace the current Map with a new one rather than calling set on it directly if we want React to recognise the update.
The update logic from the click handler should now be placed in componentDidUpdate, a lifecycle method that is invoked when the state of the component is updated. The previous props and state are passed as parameters to the componentDidUpdate function so you can figure out what changed. Even better would be to simply rely on the new state, as this has a far lower chance of breaking when new transitions and states are added.
Now, we’ve actually accomplished something: we’ve distinguished between the state representation and the state transition (opening a panel upon click) (active panel has accordion-expanded class). Doing this repeatedly for various stages will undoubtedly start to provide a clearer picture of what the code is doing and make it simpler to update for a more complicated application.
Size is important:
The example component is currently somewhat modest, but if the same procedures were followed in a larger application, a vast component would undoubtedly do a wide range of tasks (at least initially). At this point, adopting React’s component paradigm and beginning to break this down into smaller components with distinct functions is definitely a smart idea.
You have a few options, and the best choice will entirely depend on the conditions of your application. However, you don’t have to do it right the first time; this is a process that continues as you examine and modify your programme.
Additional points:
There are several additional advantages to the strategy we’ve chosen. For instance, (latest versions of) React automatically detect all coding problems and report them to a parent component for the component’s lifecycle methods and setState updater function. A minor mistake in the “old” code would instantly render your application unusable or inconsistent.
We’ll have a technique to deal with this problem using the React component. Expanding the first two panels in the example below should function normally. The third one will result in an error by producing a false bug.
The future route:
The future is promising now that we have moved our code to be usable within a React application. You can begin creating trees of components and interacting with them using properties and callbacks once more substantial chunks of code have been moved to React. As previously demonstrated, you can add error boundaries and transmit information that is pertinent to everyone using React context.
Finally, your render method can also begin rendering HTML. It should be simple to translate your componentDidUpdate to the render function if it doesn’t require previous props or state. You won’t be hindered by components that render null, so relax.
Please leave a remark below if you have any inquiries or a case you need help with, and we’ll get back to you.