React - Promise issue

Currently stuck trying to get react to get an object rather than return a promise,

Basically I have two lists of presets, user and default. I’m using a function to combine the objects and then pass it onto a .map() to render a dropdown.

Current code is

const defaultPresetsLoader = () => {

  const defaultPresets = require("../data/defaultPresets.json");

    return defaultPresets

};

const getPresets = async () => {

  const defaultPresets = defaultPresetsLoader();

  let dataFolder = await fs.getDataFolder();

  let returnFile = await dataFolder.getEntry("userPresets.json");

  let file = await returnFile.read();

  let userPresets = await JSON.parse(file);

  const presetsObject = {

    ...defaultPresets,

    ...userPresets,

  };

  console.log(presetsObject)   // This logs the object as expected

  return presetsObject

}

const presets = getPresets();

console.log(presets)  // This returns a promise

If I console.log inside the function getPresets(), it returns the object as expected. If I console.log from outside, it returns the promise.

If I swap

const presets = getPresets();

to

const presets = defaultPresetsLoader();

Then the dropdown updates with the default options as it get’s the object from that function as expected.

The dropdown it’s updating is

<sp-picker id="presetPicker" size="s" style={{ flexGrow: 1 }}>

          <sp-menu slot="options" onClick={handlePresetChange}>

            {Object.entries(presets).map(([name, data]) => (

              <sp-menu-item

                selected={preset.name === data.name ? true : null}

                id={data.id}

                key={data.id}

                value={name}

              >

                {data.name}

              </sp-menu-item>

            ))}

          </sp-menu>

        </sp-picker>

Not sure what’s wrong here although I imagine it’s something to do with async/await

Since it’s async, you should write

const presets = await getPresets();
or
getPresets().then(presets => ...);

const presets = getPresets().then(function(result) {
  console.log(result) //<returns the object 
    return result
});

console.log(presets) // still returns the promise.

I’m using react so cant use await outside a function (or at least I just get build errors if I do)

You should do something like this:

const Picker = () => {
  const [presets, setPresets] = useState({});

  useEffect(() => {
    getPresets().then(result => {
      setPresets(result)
    })
  }, [])

  return Object.keys(presets).length ? <sp-picker>...</sp-picker> : <>Loading...</>
}

I suggest to look up React hooks (specifically useState and useEffect)

1 Like

One nice little hook called useAsync that I’m using in another project can abstract the code from @Karmalakas even more. It’s part of the react-use library and handles states based on Promises for you by wrapping them in an object with the properties loading, error and value. The code would look like this if you’d decide to use it:

const Picker = () => {
  const presets = useAsync(() => getPresets(), []);
  return presets.loading ? <>Loading...</> : <sp-picker>...</sp-picker>
}

(Haven’t tested it in a Photoshop project yet but I don’t see any reason why it shouldn’t work)

1 Like