Beginner React and Javascript mistakes I've made

A running list of things I stumbled into realizing
March 16, 2021 • 1 view

I enjoy coding, but I still make some really stupid mistakes 😅. Here's a running list of things I inadvertently did until I learned otherwise, mostly React/Vue/JS/Firebase related. This list is continuously updated.


1. Never pass a deconstructed version of your redux state into a selector


/* Do not do this */
const mapState({ app, firebase }) => {...}

/* Always do this!!! */
const mapState(state) => {...}

/* for either... */ 
connect(mapState)
useSelector(mapState)

Deconstructing objects in Javascript creates a new object, meaning when you deconstruct the redux state before passing it in, it forces an update every prop update instead of when the state actually changes (which causes more needless re-renders).


2. Always name your React functional components


/* Never do this */
export default (props) => (<div></div>)

/* Name your components */
export default function Test (props) => (<div></div>)

I always preferred not naming my components and instead just exported them cause it was "cleaner" (Isn't the filename enough???). However, apparently that is terrible for the compiler, and can lead to weird errors and worse performance.


3. React.lazy is amazing

Once your React project gets too large, import your components using React.lazy can lead to a huge performance boost.


import React from 'react'

/* If you need the component immediately */
import OtherComponent from './OtherComponent';

/* If you can wait a little bit */
const OtherComponent = React.lazy(() => import('./OtherComponent'));

The benefit of React.lazy is that it'll only boot up code when you actually need it rather than having it always available. This is useful for things like loading Login/Signup pages only when users actually go to those pages. Trust me, it makes a huge difference. Learn more about how to use it here: https://reactjs.org/docs/code-splitting.html#reactlazy


4. The difference between .forEach and for...of

Can you tell the difference between


items.forEach(async item => {
  await action(item)
})

and


for (const item of items) {
  await action(item)
}

and


await Promise.all(items.map(async item => {
  await action(item)
})

These all are drastically different. Let's say action takes 1s to run and there are 10 items. The first runs the function "action" for each item in items and jumps to the next line of code before any "action" finishes (in 0s). The second runs "action" one at a time, waiting for each to finish, before going to the next lines of code (in 10s). The last runs "action" for all items in parallel and waits for all to finish before going to the next line of code (in 1s). For a while I confused all of them and would be stumped as to why changes I was expecting just weren't happening. So be warned.


5. Avoid too many Firebase listeners...

One project I started involved a commenting system, and to keep track of whether a user had upvoted a comment, I setup a listener so it would live update for each and every one. This works great with like 2 comments, but not so much with over 100. To my knowledge, it's not so much the number of listeners but rather the creating and removing them that creates a lot of overhead. When I changed it to 1 listener that fetched everything instead of 100 that fetched for each comment, page renders cutdown from 1s to <100ms.