What ReactJS is NOT made for

What ReactJS is NOT made for

When a certain tool becomes incredibly popular, it’s easy to fall into the trap of choosing the tool before knowing the problem. It’s like buying a hammer before seeing if the plans call for screws or nails.

SUMMARY

I’ve been enthusiastically learning React, without quite understanding what it was designed for and what it wasn’t. So, I tried building numerous small apps in vanilla Javascript AND React, to understand how things translate from one to the other. Here is what I learned!

What is React designed for?

React is designed for data driven dynamic sites, commonly single page apps, where data is requested from a server and then used by the browser to render pages. React helps breakdown apps into lots of little UI components, making it easier to map mentally as well as share components across large teams. Facebook is a perfect example (the creators of React).

What did I try to build?

A metronome app with no server-side programming or data to fetch from a database. Just complex client side metronome logic to create a tool for musicians.

Was I successful?

Yes, actually! But using React was more difficult, required more lines of code, and more dependencies.

The Project

My goal to re-build my SwingDivsion Metronome in React with the aim of learning more about React’s weaknesses and how to overcome them.

My Challenges, Where I found Help, and Solutions!

Challenge 1: Where to put the metronome constructor function?

For the vanilla JS version, I had created a timer constructor function (inspired by the creator of Music and Coding on YouTube). Then, I declared an instance of the timer function using my metronome’s callback and error functions. This helped me divide some of the complexity into smaller chunks. In React, I couldn’t figure out where to write my constructor function code so that it was usable for my metronome. The constructor function relied on the This keyword, which seemed to be lost in React with everything broken up into modules.

Code snippet of the vanilla JS constructor function for my metronome

^ IMG: the constructor function for my metronome

Solution

I never figured out where to write a constructor function like this, and how to use it in React, but instead, I realized I didn’t need multiple instances of the function. So, I just wrote the functional logic directly into my startStopBtn component without needing the THIS keyword.

Challenge 2: Where do states need to be managed?

My vanilla JS version didn’t need to think about state management so much because all my UI was coded in one file. Regular JS variables were declared and bound to user input via event handlers, then read into the metronome logic and UI.

In React, every UI component is its own module. So, after creating a static version of the UI, I had to consider state. Which variables need to change and which components need to receive those changes?

Solution

I mapped the component architecture and then labeled which components needed to manage which state variable by identifying the nearest common ancestor for all components reading a particular state.

Component Architecture Map

^IMG: App's component architecture and state management

UserInput module, managing state for rhythm and beatCount

^IMG: code snippet of two states being managed by the UserInputs module.

Challenge 3: How to clearTimeout when each new render loses the timeoutID?

This was my biggest hurdle! I searched far and wide for solutions, using google, StackOverflow, slack groups, and more. At least half the answers were using the older class model of React, so I had to refine my search to React with Hooks. All the solutions/examples I found were for single timeouts that needed an automatic clearTimeout in case the user didn’t actively cancel the task. My problem was different in that I had a recursive timeout and I wanted clearTimeout to be triggered by an onClick event. None of these particulars matched solutions I found.

The problem: each state change — and thus re-render — caused me to lose the timeout Id. So, when the user clicked ‘STOP’, React rendered the UI component again and lost the timeout ID, making the clearTimeout function useless. I tried useContext to maintain the timeout ID which I was losing, but that didn’t work. All of this searching prompted me to learn a lot about useState, useContext, and useEffect.

Solution

Digging deeper into the React Hooks documentation, I learned that although the useEffect hook doesn’t need to return anything (that’s typical), one can have their useEffect block return an arrow function and it will be called at the end of the components lifecycle. So, just BEFORE the next render, when the component unmounts, the useEffect is returned. With this discovery, I was able to put my metronome logic into useEffect, and return clearTimeout. That way, when the user clicked ‘STOP’, it triggered a state change, but before unmounting the component and mounting a new instance, the previous useEffect is returned, clearing the timeout before the timeout ID is lost.

The use Effect block with all my essential metronome logic and returning a clear timeout.

^IMG: Solution code snippet of the useEffect block returning a clear timeout.

Flow diagram for the order of execution for State and useEffect in React

^IMG: The order of execution for State and useEffect in React

Challenge 4: How to use HowlJS — is it even needed?

HowlJS is a great javascript library solving many web audio challenges. It was a helpful tool in my vanilla JS version of the app that allowed my audio files to interrupt themselves and replay. Without Howl, metronome clicks would be skipped until the current audio file was finished playing. NOT GOOD!

Unfortunately, my Howl audio objects were not playing in the React version. I dug into the HowlJS documentation as well as google for information and examples of how to incorporate HowlJS in a React project.

I discovered people have developed necessary React Hooks to successfully incorporate HowlJS.

Solution

Before learning the api for a new HowlJS Hook, I thought about the magic of React. How it creates a virtual DOM and renders only the UI components that change state. I tested out making the metronome without Howl, and after some hurdles, it worked! The issue vanilla JS had with re-playing an audio file over itself was already solved by React’s state magic.

Conclusion

React is designed for dynamic data driven sites, where data is requested from a server and then used by the client’s browser to render pages. React enables engineers to encapsulate UI components into modules that can manage their own state. This helps large organizations manage apps with lots of components. My metronome app isn’t requiring a large team to collaborate on, nor does it need to pull data from a server. So, React was not the best tool for the job. However, I do recommend this study method for learning React, or any other javascript framework/library.

First, build a project in vanilla JS, since at the core, that’s what all these front-end frameworks are transpiling to. The better you understand vanilla JS, the easier you will be able to work with higher level frameworks.

Second, try and rebuild the app using React or whatever framework you want to study. Be patient with the challenges. Remember, your goal isn’t the finished product, it is to learn. So, welcome the challenges and all the solution digging they require!

要查看或添加评论,请登录

Michael Galen的更多文章

社区洞察

其他会员也浏览了