0

I have a situation where on one screen (AScreen), I load JSON data from a .json file, I also have a Settings screen where the user can set 'settingA' as true or false.

AScreen (basically if settingA is set to true, load two JSON files, if settingA is false, load only one data file):

import React, { useContext } from 'react';
import { SettingsContext } from '../context/settingsContext';

const AScreen = () => {
  const { settingA } = useContext(SettingsContext);

  const loadedData = (() => {
    if (settingA === true) {
      console.log('True');
      return Object.assign(
        require('../assets/data/jsonFileA.json'),
        require('../assets/data/jsonFileB.json')
      )
    }
    console.log('False');
    return require('../assets/data/jsonFileA.json')
  })();

  console.log(settingA):
  console.log(loadedData);

  return (
    ...
  );
};

The issue here is that if I load the app and head to AScreen, I get the correct data loaded into loadedData. However, if I then head to the settings page and change the setting then go back to AScreen, the console.log(settingA) shows the updated setting and the correct 'True' or 'False' is printed but the loadedData still contains the data from the first time I visited AScreen.

This tells me that the require() function doesn't actually get called until the screen is fully re-rendered.

Is there a better way to load JSON data than require()? Or how can I make sure require() is called every time the screen is displayed even if the screen isn't re-rendered.

I know one option would be to load all the JSON data then simply filter it based on the user's settings but in the actual app there are a lot more data files so it seems that would be a waste of resources to load all the files at once.

John
  • 497
  • 2
  • 16
  • You need a screen focus handler effect – Mechanic Feb 19 '22 at 22:57
  • @Mhmdrz_A Would that cause the require() to actually run again? The section of code where require() is located certainly runs already. How would a focus handler cause the require() function to actually pull the data again? – John Feb 19 '22 at 23:04

2 Answers2

0

Delete the require cache

delete require.cache[require.resolve('../assets/data/jsonFileA.json')];
...
kelsny
  • 23,009
  • 3
  • 19
  • 48
  • Would that simply be calling 'delete' before the 'const loadedData(() => {})' call? – John Feb 19 '22 at 23:02
0

Regardless of how many ways I tried setting loadedData to {}, running the delete require.cache[] command, using let instead of const, etc. I always ended up the same with the loadedData not updating properly.

It turns out that the issue was from the Object.assign() function. Instead of using:

return Object.assign(
  require('../assets/data/jsonFileA.json'),
  require('../assets/data/jsonFileB.json')
)

I used:

return Object.assign(
  {},
  require('../assets/data/jsonFileA.json'),
  require('../assets/data/jsonFileB.json')
)

where the {} basically unsets the target, which is 'loadedData' and resets it with the new data. Without {}, the require statements only updated the location in memory where the require() function originally placed the data, therefore I wasn't getting the changes I was looking for.

Warning for anyone needing this in the future: The Object.assign() method creates a shallow copy so if the source changes, then the target also will change. Other methods will be necessary if you want a completely new object in memory.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

John
  • 497
  • 2
  • 16