Top 5 bugs in my ReactJS applications

More than 4 years ago, I fell in love with ReactJS and since then I have been developing all Front End applications with this wonderful tool. During this time, I and the teams that I was lucky to work in made a bunch of mistakes, many of which were successfully fixed. Many optimal solutions have been found in difficult and expensive experiments.



Today I want to share the most critical and painful mistakes that are made more often than others. Before writing this article, I, of course, studied the Internet in search of similar articles, and I was surprised to find that most of them are outdated and talk about things that are of little relevance in 2019. So, I tried to compile a list of the most pressing problems at the moment.



How I worked on a ReacjJS application



1. Stateful components (classes) are worse than hooks



Perhaps it’s worth starting with the most sensational ReactJS feature, which appeared in version 16.8+ Contrary to some beliefs, this feature was plagued by errors of previous generations of developers and solves many problems. If you are still using class components instead of hooks in 2019, then you are making a big mistake and just do not understand what their advantage is. I will not explain this in detail in this article, look better this wonderful video by Den Abramov , but I just could not start this article otherwise



This, of course, is not a mistake in itself, but the approach of classes compared to hooks is much more error prone, as many articles have already been written about:



  1. The most common mistakes in your React code that you (possibly) make
  2. The 7 Most Common Mistakes that React Developers Make


2. Using anonymous functions as props



If the first error can still be perceived as a tribute to fashion, then the knowledge of the second, I assure you, will save you from sleepless nights and headaches. After all, it is she who makes the application work so inadequately that its users can forever be disappointed in ReactJS . But we want users to love him, just like you and me, right? To avoid this error, you can use a very simple rule - never, NEVER pass an anonymous function to the component as props.



export default function MyOtherComponent() { return ( <MyComponent getValue={i => i.value} /> {/*     */} ); }
      
      





A more sophisticated version of this error may look something like this (do not read if you are not familiar with Redux):



 import { connect } from 'react-redux'; import { createStructuredSelector } from 'reselect'; import MyComponent from './MyComponent'; import { fetchProjectData, projectId } from "./store/projects" const mapStateToProps = createStructuredSelector({ projectId, }); const mapDispatchToProps = { fetchProjectData, }; const mergeProps = ( { projectId, ...restState }: any, { fetchProjectData, ...restDispatch }: any, { memberId, ...restOwn }: any ) => ({ ...restState, ...restDispatch, ...restOwn, fetchProjectData: () => fetchProjectData(projectId), }); export default connect( mapStateToProps, mapDispatchToProps, mergeProps )(MyComponent);
      
      





In both cases, in the end, an anonymous function gets into the props component. This is bad because with each render of the parent element, this function will refer to a new object in memory, which means that it will not be equal to the previous one, and your component will be successfully rendered unnecessarily. It can slow down the performance of your application so much that you yourself will start to spit and become disappointed in React , but the whole point is in ANONYMOUS FUNCTIONS in props . Just never do it - and be happy.



The problem is that, often such an error does nothing wrong. The code just works for itself - and that’s it. And nothing noticeably bad happens. Exactly until the moment you once again push the anonymous call to receive data from the server there (second example), then you will understand the seriousness of the problem. The accumulation of such anonymous props, as a result, will slow down your application to the level of experience in 1995, when we had to ask the neighbors to release the telephone line to download the page.



Just a few words, how to write correctly. Here's how:



 const getValue = i => i.value; return default function MyOtherComponent() { return ( <MyComponent getValue={getValue} /> ); }
      
      





 import { connect } from 'react-redux'; import { createStructuredSelector } from 'reselect'; import MyComponent from './MyComponent'; import { fetchProjectData, projectId } from "./store/projects" const mapStateToProps = createStructuredSelector({ projectId, }); const mapDispatchToProps = { fetchProjectData, }; export default connect( mapStateToProps, mapDispatchToProps )(MyComponent); //     import React, { useEffect } from 'react'; export default function MyComponent({ fetchProjectData, projectId }) { useEffect(() => { fetchProjectData(projectId); }, [fetchProjectData, projectId]); return ( <div>{/* -  */}</div> ); } //        ,       , ..     . , -   ,     .
      
      





3. Multiple React Instances in the Application



This error most likely relates to the architecture of the entire application as a whole, and not just ReactJS in particular. But this practical problem is often too expensive for developers and too often for sleepless nights.



Please do not try to cram more than one instance of the React application on one page. In fact, in the React documentation there is no ban on this approach, I even met recommendations to do just that in some articles (and, of course, I did this in my applications), BUT optimizing this approach and harmonizing all parts of the application, in this case begins to take up more than half of all working time. This can be easily avoided: for example, if you need to respond to some events in legacy code in your new React application, you can use the event model. For example, like this:



 import React, { useCallback, useEffect } from 'react'; export default function MyComponent() { const reactHandlerOfLegacyEvent = useCallback((event) => {/* event handler */}, []); useEffect(() => { document.addEventListener("myLegacyEvent", reactHandlerOfLegacyEvent); return () => { document.removeEventListener("myLegacyEvent", reactHandlerOfLegacyEvent); }; }, [reactHandlerOfLegacyEvent]); return ({/*  -  */}); }
      
      





4. Writing your own libraries, instead of existing open source



This problem is not about ReactJS at all, but about the whole development. Of course, while you are just learning, writing a large number of your own libraries will allow you to grow faster and get bigger, but if you want to be at the forefront of programming, you just have to at least try each of the open source libraries that solve your problems. Just ask the search robots if there are any libraries that solve your problem - they can answer such questions perfectly.



I will not give an example of libraries that I use myself, because I know that half of them will become obsolete in a couple of months and others will come in their place. And, it would seem, this contradicts the original statement. And really, why use libraries that become obsolete in a couple of months? The answer is very simple - you can see the solution to those problems that have not yet arisen before you. You can improve existing developments, or understand how to solve the problem much better by the example of problems in existing libraries. This can only be done by interacting with the development world through the use of open source libraries.



5. Fear of using someone else's code



Like the previous error, this is not unique to ReactJS applications, but it is quite common in them. How often do I see how a great June bravely breaks into battle and rewrites parts of the code that work fine and that have no problems, just because they read about one of the previous 4 errors. I myself was like that. But what is there to cheat, I often waste time now, simply because movement is life.



But I also learned to understand other developers, their thoughts and problems that they encountered. See the amount of time and effort that has been spent (and not in vain) on solving problems. In 3 cases out of 5, when I try to “improve” someone else’s code, I get almost the same result as I did. Just because at the start of the task, you usually do not see all the problems that lie ahead in the future. So, now I respect someone else’s code, no matter how strange and “outdated” it seems to me. Which I advise you.



thank



Thank you for reading this article and all those with whom I am fortunate to work together. Thanks to us for making our world more interesting and moving it forward. Let not always right, not always skillfully, but move.



Write about the problems you encountered in the comments. Perhaps you have solutions to the problems described in this article that I have missed (I am sure that this is so). All success and good mood!



All Articles