8 Practices In React That Will Crash Your App In The Future
Tags: react, javascript, node, webdev
Published: 2019-07-04 04:31:51

Find me on [medium](https://medium.com/@jsmanifest)!

__Edit__: Point __#2__ of this post has been revised to be more understandable (and creepier) in a reader’s perspective. Thank you to the user on dev.to who emailed me about the previous confusion!

A lot of us have fallin in love with the react library for several reasons. It _can_ be incredibly painless to create complex interactive user interfaces. The greatest part of it all is being able to compose components right on top of another without breaking other composed components.

And it's amazing that even social media giants like [Facebook](https://www.facebook.com), [Instagram](https://www.instagram.com) and [Pinterest](https://www.pinterest.com) made [heavy use of them](https://brainhub.eu/blog/10-famous-apps-using-reactjs-nowadays/) while creating a seamless user experience with huge APIs like [Google Maps](https://cloud.google.com/maps-platform/?&sign=0) .

If you're currently building an application using react or thinking of using react for upcoming projects, then this tutorial is for you. I hope this tutorial will help _you_ on your journey to make great react applications too by exposing a few code implementations that you ought to think twice about.

Without further ado, here are 8 Practices In React That Will Crash Your App In The Future:

## 1. Declaring Default Parameters Over Null

I mentioned this topic in an [earlier article](https://medium.com/better-programming/10-things-not-to-do-when-building-react-applications-bc26d4f38644), but this is one of those creepy "gotchas" that can fool a careless developer on a gloomy friday! After all, apps crashing is _not a joke_--any type of crash can result in money loss at any point in time if not handled correctly.

I was once guilty of spending a good amount of time debugging something similar to this:

```jsx
const SomeComponent = ({ items = [], todaysDate, tomorrowsDate }) => {
  const [someState, setSomeState] = useState(null)

  return (
    <div>
      <h2>Today is {todaysDate}</h2>
      <small>And tomorrow is {tomorrowsDate}</small>
      <hr />
      {items.map((item, index) => (
        <span key={`item_${index}`}>{item.email}</span>
      ))}
    </div>
  )
}

const App = ({ dates, ...otherProps }) => {
  let items
  if (dates) {
    items = dates ? dates.map((d) => new Date(d).toLocaleDateString()) : null
  }

  return (
    <div>
      <SomeComponent {...otherProps} items={items} />
    </div>
  )
}
```

Inside our App component, if dates ends up being falsey, it will be initialized with null.

If you're like me, our instincts tell us that items should be initialized to an empty array by default if it was a falsey value. But our app will crash when dates is falsey because items is null. _What_?

Default function parameters allow named parameters to become initialized with default values if no value or undefined is passed!

In our case, even though null is falsey, it's still a value!

So the next time you set a default value to _null_, just make sure to think twice when you do that. You can simply just initialize a value to an empty array if that is the expected type of the value.

## 2. Grabbing Properties With Square Brackets

Sometimes the way properties are being grabbed may influence the behavior of the app. If you're wondering what that behavior is, it's the app crashing. Here is an example of performing object lookups with square brackets:

```js
const someFunction = function() {
  const store = {
    people: {
      joe: {
        age: 16,
        gender: 'boy',
      },
      bob: {
        age: 14,
        gender: 'transgender',
      }
    }
  }
  return {
    getPersonsProfile(name) {
      return store.people[name]
    },
    foods: ['apple', 'pineapple'],
  }
}

const obj = someFunction()
const joesProfile = obj.getPersonsProfile('joe')

console.log(joesProfile)
/*
  result: 
      {
        age: 16,
        gender: boy,
      }
*/
```

These are actually 100% valid use cases and there's nothing really wrong with them besides [being slower than object key lookups](https://stackoverflow.com/questions/26353417/javascript-object-vs-array-lookup-performance/26353637).

Anyhow, the real problem starts to creep up on your app when an unintentional issue occurs, like a tiny typo:

```js
const someFunction = function () {
  const store = {
    people: {
      joe: {
        age: 16,
        gender: 'boy',
      },
      bob: {
        age: 14, 
      gender: 'transgender',
      }
    }
  }
  return {
    getPersonsProfile(name) {
      return store.people[name]
    },
    foods: ['apple', 'pineapple'],
  }
}

const obj = someFunction()
const joesProfile = obj.getPersonsProfile('Joe')
const joesAge = joesProfile.age

console.log(joesAge)
```

If you or one of your teammates were implementing some enhancement to this snippet and made a minor mistake (such as capitalizing the *J* in *joe*), the result will immediately return _undefined_, and a crash will occur:

```jsx
"TypeError: Cannot read property 'age' of undefined
    at tibeweragi.js:24:29
    at https://static.jsbin.com/js/prod/runner-4.1.7.min.js:1:13924
    at https://static.jsbin.com/js/prod/runner-4.1.7.min.js:1:10866"
```

The creepy part is, the app _will not crash_ until a part of your code attempts to do a property lookup with that undefined value!

So in the mean time, joes profile (_undefined_ in disguise) will be passed around your app and no one will be able to know that this hidden bug is creeping around until a piece of a code performs some property lookup, like _joesProfile.age_, because _joesProfile_ is `undefined`!

What some developers do to avoid a crash is to initialize some default valid return value if a lookup ends up becoming unsuccessful:

```jsx
const someFunction = function () {
  const store = {
    people: {
      joe: {
        age: 16,
        gender: 'boy',
      },
      bob: {
        age: 14, 
      gender: 'transgender',
      }
    }
  }
  return {
    getPersonsProfile(name) {
      return store.people[name] || {}
    },
    foods: ['apple', 'pineapple'],
  }
}
```

At least now the app won't crash. The moral of the story is, always _handle an invalid lookup case when you're applying lookups with square bracket notation_!

For some, it might be a little hard to explain the severity of this practice without a real world example. So I'm going to bring up a real world example. The code example I am about to show you was taken from a repository that dates 8 months back from today. To protect some of the privacy that this code originated from, I renamed almost every variable but the _code design, syntax and architecture stayed exactly the same_:

```jsx
import { createSelector } from 'reselect'

// supports passing in the whole obj or just the string to correct the video type
const fixVideoTypeNaming = (videoType) => {
  let video = videoType

  // If video is a video object
  if (video && typeof video === 'object') {
    const media = { ...video }
    video = media.videoType
  }

  // If video is the actual videoType string
  if (typeof video === 'string') {
    // fix the typo because brian is an idiot
    if (video === 'mp3') {
      video = 'mp4'
    }
  }

  return video
}

/* -------------------------------------------------------
  ---- Pre-selectors
-------------------------------------------------------- */

export const getOverallSelector = (state) =>
  state.app[fixVideoTypeNaming(state.app.media.video.videoType)].options.total
    .overall

export const getSpecificWeekSelector = (state, props) =>
  state.app[fixVideoTypeNaming(state.app.media.video.videoType)].options.weekly[
    props.date
  ]

/* -------------------------------------------------------
  ---- Selectors
-------------------------------------------------------- */

export const getWeeklyCycleSelector = createSelector(
  getSpecificWeekSelector,
  (weekCycle) => weekCycle || null,
)

export const getFetchingTotalStatusSelector = createSelector(
  (state) =>
    state.app[fixVideoTypeNaming(state.app.media.video.videoType)].options.total
      .fetching,
  (fetching) => fetching,
)

export const getFetchErrorSelector = createSelector(
  (state) =>
    state.app[fixVideoTypeNaming(state.app.media.video.videoType)].options.total
      .fetchError,
  (fetchError) => fetchError,
)
```

_fixVideoTypeNaming_ is a function that will extract the video type based on the value passed in as arguments. If the argument is a video _object_, it will extract the video type from the _.videoType_ property. If it is a string, then the caller passed in the videoType so we can skip first step. Someone has found that the videoType _.mp4_ property had been mispelled in several areas of the app. For a quick temporary fix around the issue, _fixVideoTypeNaming_ was used to patch that typo.

Now as some of you might have guessed, the app was built with [redux](https://redux.js.org/) (hence the syntax).

And to use these selectors, you would import them to use in a [connect](https://react-redux.js.org/api/connect) higher order component to attach a component to listen to that slice of the state.

```jsx
const withTotalCount = (WrappedComponent) => {
  class WithTotalCountContainer extends React.Component {
    componentDidMount = () => {
      const { total, dispatch } = this.props
      if (total == null) {
        dispatch(fetchTotalVideoTypeCount())
      }
    }

    render() {
      return <WrappedComponent {...this.props} />
    }
  }

  WithTotalCountContainer.propTypes = {
    fetching: PropTypes.bool.isRequired,
    total: PropTypes.number,
    fetchError: PropTypes.object,
    dispatch: PropTypes.func.isRequired,
  }

  WithTotalCountContainer.displayName = `withTotalCount(${getDisplayName(
    WrappedComponent,
  )})`

  return connect((state) => {
    const videoType = fixVideoTypeNaming(state.app.media.video.videoType)
    const { fetching, total, fetchError } = state.app.media.video[
      videoType
    ].options.total

    return { fetching, total, fetchError }
  })(WithTotalCountContainer)
}
```

UI Component:

```jsx
const TotalVideoCount = ({ classes, total, fetching, fetchError }) => {
  if (fetching) return <LoadingSpinner />
  const hasResults = !!total
  const noResults = fetched && !total
  const errorOccurred = !!fetchError

  return (
    <Typography
      variant="h3"
      className={classes.root}
      error={!!fetched && !!fetchError}
      primary={hasResults}
      soft={noResults || errorOccurred}
      center
    >
      {noResults && 'No Results'}
      {hasResults && `$${formatTotal(total)}`}
      {errorOccurred && 'An error occurred.'}
    </Typography>
  )
}
```

The component receives all of the props that the HOC passes to it and displays information following the conditions adapting from the data given from the props. In a perfect world, this would be fine. In a non-perfect world, this would _temporarily_ be fine.

If we go back to the container and look at the way the selectors are selecting their values, we actually might have planted a ticking timebomb waiting for an open opportunity to attack:

```js
export const getOverallSelector = (state) =>
  state.app[fixVideoTypeNaming(state.app.media.video.videoType)].options.total
    .overall

export const getSpecificWeekSelector = (state, props) =>
  state.app[fixVideoTypeNaming(state.app.media.video.videoType)].options.weekly[
    props.date
  ]
```

When developing _any_ sort of application, common practices to ensure higher level of confidence and diminishing bugs during the development flow is implementing [tests](https://codeahoy.com/2016/07/05/unit-integration-and-end-to-end-tests-finding-the-right-balance/) in-between to ensure that the application is working as intended.

In the case of these code snippets however, if they aren't tested, the app _will_ crash in the future if not handled early.

For one, _state.app.media.video.videoType_ is _four_ levels deep in the chain. What if another developer accidentally made a mistake when he was asked to fix another part of the app and _state.app.media.video_ becomes _undefined_? The app will crash because it can't read the property _videoType of undefined_.

In addition, if there was another typo issue with a _videoType_ and _fixVideoTypeNaming_ isn't updated to accomodate that along with the _mp3_ issue, the app risks another unintentional crash that no one would have been able to detect unless a _real user_ comes across the issue. And by that time, it would be _too late_.

And it's _never_ a good practice to assume that the app will never ever come across bugs like these. Please be careful!

## 3. Carelessly Checking Empty Objects When Rendering

Something I used to do long ago in the golden days when conditionally rendering components is to check if data had been populated in objects using `Object.keys`. And if there were data, then the component would continue to render if the condition passes:

```jsx
const SomeComponent = ({ children, items = {}, isVisible }) => (
  <div>
    {Object.keys(items).length ? (
      <DataTable items={items} />
    ) : (
      <h2>Data has not been received</h2>
    )}
  </div>
)
```

Lets pretend that we called some API and received _items_ as an object somewhere in the response. With that said, this may seem perfectly fine at first. The expected type of _items_ is an object so it would be perfectly fine to use _Object.keys_ with it. After all, we _did_ initialize items to an empty object as a defense mechanism if a bug were to ever appear that turned it into a falsey value.

But we shouldn't trust the server to _always return the same structure_. What if items became an array in the future? `Object.keys(items)` would _not crash_ but would return a weird output like `["0", "1", "2"]`. How do you think the components being rendered with that data will react?

But that's not even the worst part. The worst part in the snippet is that if _items_ was received as a _null_ value in the props, then `items` [will not even be initiated to the default value you provided](https://medium.com/better-programming/10-things-not-to-do-when-building-react-applications-bc26d4f38644)!

And _then your app will crash before it begins to do anything else_:

```js
"TypeError: Cannot convert undefined or null to object
    at Function.keys (<anonymous>)
    at yazeyafabu.js:4:45
    at https://static.jsbin.com/js/prod/runner-4.1.7.min.js:1:13924
    at https://static.jsbin.com/js/prod/runner-4.1.7.min.js:1:10866"
```

Again, please be careful!

## 4. Carelessly Checking If Arrays Exist Before Rendering

This can be a very similar situation as with #3, but arrays and objects are used quite often interchangeably that they deserve their own sections.

If you have a habit of doing this:

```jsx
render() {
  const { arr } = this.props
  return (
    <div>
      {arr && arr.map()...}
    </div>
  )
}
```

Then make sure you at least have unit tests to keep your eyes on that code at all times or handle `arr` correctly early on before passing it to the render method, or else the app will crash if `arr` becomes an _object literal_. Of course the `&&` operator will consider it as _truthy_ and attempt to _.map_ the object literal which will end up crashing the entire app.

So please keep this in mind. Save your energy and frustrations for bigger problems that deserve more of your special attention! ;)

## 5. Not Using a Linter

If you aren't using any type of linter while you're developing apps or you simply don't know what they are, allow me to elaborate a little about why they are useful in development.

The linter I use to assist me in my development flow is [ESLint](https://eslint.org/), a very known linting tool for JavaScript that allows developers to discover problems with their code without even executing them.

This tool is so useful that it can act as your semi-mentor as it helps correct your mistakes in real time--as if someone is mentoring you. It even _describes why your code can be bad_ and suggests what you should do to replace them with!

Here's an example:

![eslint](https://jsmanifest.s3-us-west-1.amazonaws.com/posts/8-practices-in-react-that-will-crash-your-app-in-the-future/eslint.jpg)

The coolest thing about eslint is that if you don't like certain rules or don't agree with some of them, you can simple disable certain ones so that they no longer show up as linting warnings/errors as you're developing. _Whatever makes you happy_, right?

## 6. Destructuring When Rendering Lists

I've seen this happen to several people in the past and it isn't always an easy bug to detect. Basically when you have a list of items and you're going to render a bunch of components for each one in the list, the bug that can creep up on your app is that if there comes a time in the future where one of the items in the list is not a value you expect it to be, your app may crash if it doesn't know how to handle the value type.

Here's an example:

```jsx
const api = {
  async getTotalFrogs() {
    return {
      data: {
        result: [
          { name: 'bob the frog', tongueWidth: 50, weight: 8 },
          { name: 'joe the other frog', tongueWidth: 40, weight: 5 },
          { name: 'kelly the last frog', tongueWidth: 20, weight: 2 },
        ],
      },
    }
  },
}

const getData = async ({ withTongues = false }) => {
  try {
    const response = await api.getTotalFrogs({ withTongues })
    return response.data.result
  } catch (err) {
    throw err
  }
}

const DataList = (props) => {
  const [items, setItems] = useState([])
  const [error, setError] = useState(null)

  React.useEffect(() => {
    getData({ withTongues: true })
      .then(setItems)
      .catch(setError)
  }, [])

  return (
    <div>
      {Array.isArray(items) && (
        <Header size="tiny" inverted>
          {items.map(({ name, tongueWidth, weight }) => (
            <div style={{ margin: '25px 0' }}>
              <div>Name: {name}</div>
              <div>Width of their tongue: {tongueWidth}cm</div>
              <div>Weight: {weight}lbs</div>
            </div>
          ))}
        </Header>
      )}
      {error && <Header>You received an error. Do you need a linter?</Header>}
    </div>
  )
}
```

![frogs1](https://jsmanifest.s3-us-west-1.amazonaws.com/posts/8-practices-in-react-that-will-crash-your-app-in-the-future/frogs1.JPG)

The code would work perfectly fine. Now if we look at the api call and instead of returning this:

```jsx
const api = {
  async getTotalFrogs() {
    return {
      data: {
        result: [
          { name: 'bob the frog', tongueWidth: 50, weight: 8 },
          { name: 'joe the other frog', tongueWidth: 40, weight: 5 },
          { name: 'kelly the last frog', tongueWidth: 20, weight: 2 },
        ],
      },
    }
  },
}
```

What if somehow there was an issue with how the data flow was handled when an unexpected condition occurred in the api client and returned this array instead?

```jsx
const api = {
  async getTotalFrogs() {
    return {
      data: {
        result: [
          { name: 'bob the frog', tongueWidth: 50, weight: 8 },
          undefined,
          { name: 'kelly the last frog', tongueWidth: 20, weight: 2 },
        ],
      },
    }
  },
}
```

Your app will crash because it doesn't know how to handle that:

```jsx
Uncaught TypeError: Cannot read property 'name' of undefined
    at eval (DataList.js? [sm]:65)
    at Array.map (<anonymous>)
    at DataList (DataList.js? [sm]:64)
    at renderWithHooks (react-dom.development.js:12938)
    at updateFunctionComponent (react-dom.development.js:14627)
```

So to prevent your app from crashing instead, you can set a default object on each iteration:

```jsx
{
  items.map(({ name, tongueWidth, weight } = {}) => (
    <div style={{ margin: '25px 0' }}>
      <div>Name: {name}</div>
      <div>Width of their tongue: {tongueWidth}cm</div>
      <div>Weight: {weight}lbs</div>
    </div>
  ))
}
```

And now your users won't have to make judgements about your technology and expertise when they don't see a page crashing in front of them:

![frogs2](https://jsmanifest.s3-us-west-1.amazonaws.com/posts/8-practices-in-react-that-will-crash-your-app-in-the-future/frogs2.jpg)

However, even though the app no longer crashes I recommend to go further and handle the missing values like returning null for entire items that have similar issues instead, since there isn't any data in them anyways.

## 7. Not Researching Enough About What You're Going To Implement

One crucial mistake i've made in the past was being overly confident with a search input I had implemented, trusting my opinions too early in the game.

What do I mean by this? Well, its not the search input _component_ that I was overly confident with. The component _should have been an easy_ task... and it was.

The real culprit of an issue that occurred with the whole the search functionality was the _characters being included in the queries_.

When we're sending keywords as queries to a search API, it's not always sufficient to think that every key the user types is valid, even though they're on the keyboard for that reason.

Just be 100% sure that a regex like this works just as intended and avoids leaving out any invalid characters that can crash your app:

```jsx
const hasInvalidChars = /^.*?(?=[\+\^#%&$\*:<>\?/\{\|\}\[\]\\\)\(]).*$/g.test(
  inputValue,
)
```

That example is the most up to date, established regular expression for a search API.

Here is what it was before:

```jsx
const hasInvalidChars = /^.*?(?=[\+\^#%&$\*:<>\?/\{\|\}\[\]\)\(]).*$/g.test(
  inputValue,
)

const callApi = async (keywords) => {
  try {
    const url = `https://someapi.com/v1/search/?keywords=${keywords}/`
    return api.searchStuff(url)
  } catch (error) {
    throw error
  }
}
```

As you can see the slash `/` is missing, and that was causing the app to crash! if that character ends up being sent to an API over the wire, guess what the API thinks the URL is going to be?

Also, I wouldn't put 100% of my trust in the examples you find on the internet. A lot of them aren't fully tested solutions and there isn't really a standard for majority of use cases when it comes to regular expressions.

## 7. Not Restricting The Sizes of File Inputs

Restricting the sizes of files that users select is a good practice because most of the time you don't really need a rediculously large file when it can be compressed in some way without losing any noticeable signs of reduction in quality.

But there's a more important reason why restricting sizes to a certain limit is a good practice. At my company, we've noticed users in the past occasionally get "frozen" _while_ their images are being uploaded. Not everyone has an Alienware 17 R5 in their possession, so you must take certain circumstances of your users in consideration.

Here's an example of restricting files to a limit of 5 MB (5,000,000 bytes):

```jsx
import React, { useState, useEffect } from 'react'

const useUploadStuff = () => {
  const [files, setFiles] = useState([])

  // Limit the file sizes here
  const onChange = (e) => {
    const arrFiles = Array.from(e.target.files)
    const filesUnder5mb = arrFiles.filter((file) => {
      const bytesLimit = 5000000
      if (file.size > bytesLimit) {
        // optionally process some UX about this file size
      }
      return file.size < bytesLimit
    })
    setFiles(filesUnder5mb)
  }

  useEffect(() => {
    if (files.length) {
      // do something with files
    }
  }, [files])

  return {
    files,
    onChange,
  }
}

const UploadStuff = () => {
  const { onChange } = useUploadStuff()

  return (
    <div>
      <h2 style={{ color: '#fff' }}>Hi</h2>
      <div>
        <input
          style={{ color: '#fff' }}
          onChange={onChange}
          type="file"
          placeholder="Upload Stuff"
          multiple
        />
      </div>
    </div>
  )
}

export default UploadStuff
```

You wouldn't want users to be uploading video games when they're supposed to be uploading documents!

## Conclusion

And that concludes the end of this post!

There will be a part 2 as I've only gotten through half of my list (yikes!)

Anyhow, Thank you for reading and make sure to follow me for future updates! Happy 4th of july!

Find me on [medium](https://medium.com/@jsmanifest)!