Global variables in React

Wordpressor picture Wordpressor · Nov 10, 2017 · Viewed 7.7k times · Source

I know Redux solves this but I came up with an idea.

Imagine I have an app that gets some JSON on start. Based on this JSON I'm setting up the environment, so let's assume the app starts and it downloads an array of list items.

Of course as I'm not using Redux (the app itself is quite simple and Redux feels like a huge overkill here) if I want to use these list items outside of my component I have to pass them down as props and then pass them as props again as deep as I want to use them.

Why can't I do something like this:

fetch(listItems)
  .then(response => response.json())
  .then(json => {
    window.consts = json.list;

This way I can access my list anywhere in my app and even outside of React. Is it considered an anti-pattern? Of course the list items WON'T be changed EVER, so there is no interaction or change of state.

Answer

enapupe picture enapupe · Nov 10, 2017

What I usually do when I have some static (but requested via API) data is a little service that acts kind like a global but is under a regular import:

// get-timezones.js
import { get } from '../services/request'

let fetching = false
let timez = null
export default () => {
  // if we already got timezones, return it
  if (timez) {
    return new Promise((resolve) => resolve(timez))
  }

  // if we already fired a request, return its promise
  if (fetching) {
    return fetching
  }

  // first run, return request promise
  // and populate timezones for caching
  fetching = get('timezones').then((data) => {
    timez = data
    return timez
  })
  return fetching
}

And then in the view react component:

// some-view.js
getTimezones().then((timezones) => {
  this.setState({ timezones })
})

This works in a way it will always return a promise but the first time it is called it will do the request to the API and get the data. Subsequent requests will use a cached variable (kinda like a global).

Your approach may have a few issues:

  • If react renders before this window.consts is populated you won't be able to access it, react won't know it should re-render.
  • You seem to be doing this request even when the data won't be used.

The only downside of my approach is setting state asynchronously, it may lead to errors if the component is not mounted anymore.