My forge storage reset doesn't work. Why? (Await/Async/onClick issue?)

I have been trying to create a test component that displays, clears, and default-fills the App storage.

The display works, that is, I get a nice JSON of my app storage with this component render function. (At some earlier point in my little project I created that storage content, so there is something to fetch.) In my DL_AppStorage_Render function, I can get both the space and storage info (and storage calls that same fetchSpace function.

But when I click any one of the buttons, the onClick= function is called (OK), but when that one calls storage.query or api, these seem never to return (NOT OK).

There must be something in the philosophy that I do not understand (and I am new to much of this, so that is not surprising…). Here is the relevant code:

// We are using forge's storage API. This data is only available in this app on this site
const resetGlobalDLDict = async ( spaceKey, calledfrom) => {
  console.log( `resetGlobalDLDict ${spaceKey} ${calledfrom}`);
  const space = await fetchSpace(spaceKey, calledfrom);
  console.log( `resetGlobalDLDict: All info about my space: ${JSON.stringify(space, null, 2)}`);
  await deleteAppStorage();
  storage.set( 'DL-spaceId', space.id);
  storage.set( 'DL-storage-savedAt', Math.random().toString(36).substr(2, length));
  storage.set( 'DL-storage-dummy', 1);
};

const getGlobalDLDict = async ( spaceKey, calledfrom) => {
  console.log( `getGlobalDLDict ${spaceKey} ${calledfrom}`);
  const myDict = await storage.query()
    .limit( 10)
    .getMany();
  console.log(`getGlobalDLDict: All info about my storage: ${JSON.stringify(myDict, null, 2)}`);
  return myDict;
};

const deleteAppStorage = async () => {
  console.log( `deleteAppStorage`);
  const myDict = await storage.query()
        .limit( 20)
        .getMany();
  console.log(`deleteAppStorage: All info about my storage: ${JSON.stringify(myDict, null, 2)}`);
  myDict.results.forEach(function (i) { console.log(`deleting ${i.key}`); storage.delete(i.key);});
  return;
}

const fetchSpace = async (spaceKey, calledfrom) => {
  console.log( `fetchSpace ${spaceKey} ${calledfrom}`);
  if (calledfrom === 'trigger') {
    const res = await api
      .asApp()
      .requestConfluence(route`/wiki/api/v2/spaces?keys=${spaceKey}`);

    const data = await res.json();
    console.log( `fetchSpace: will return`);
    return data.results;
  }
  else {
    const res = await api
      .asUser()
      .requestConfluence(route`/wiki/api/v2/spaces?keys=${spaceKey}`);
  
    const data = await res.json();
    console.log( `fetchSpace: will return`);
    return data.results;
  }
};

const DL_AppStorage_Render = () => {
  console.log(`DL_AppStorage_Render`);
  const context = useProductContext();
  const [mySpace] = useState(async () => await fetchSpace(context.spaceKey, 'render'));
  console.log(`DL_AppStorage_Render: All info about my space: ${JSON.stringify(mySpace, null, 2)}`);
  const [myDict] = useState(async () => await getGlobalDLDict(context.spaceKey, 'render'));
  console.log(`DL_AppStorage_Render: All info about my dict: ${JSON.stringify(myDict, null, 2)}`);

  return (
    <Fragment>
      <Code text={JSON.stringify(myDict, null, 2)} language="json" />
      <Button
        text="Remove All"
        onClick={async () => {
          deleteAppStorage();
        }}/>
      <Button
        text="Basic Fill"
        onClick={async () => {
          resetGlobalDLDict(context.spaceKey, 'button');
        }}/>
    </Fragment>
  );
};

export const dl_renderAppStorage = render(<Macro app={<DL_AppStorage_Render />}/>);

Hi @GerbenWierda,

I believe your problem is that you’re calling async functions without using await. Your Forge functions are being invoked, but exits as soon as they get to some kind of asynchronous operation. To fix this, change your anonymous Button onClick handlers as follows:

  <Button
    text="Remove All"
    onClick={async () => {
      await deleteAppStorage(); // NOTE: await added on this line
    }}/>
  <Button
    text="Basic Fill"
    onClick={async () => {
      await resetGlobalDLDict(context.spaceKey, 'button'); // NOTE: await added on this line
    }}/>

Regards,
Dugald

Thank you. This has taught me something about await/async. I was calling a function which returns a promise and I wasn’t waiting for the result. I was assuming the function would be executed nonetheless, just the result is going nowhere. But it seems that as soon as there is nobody waiting, the whole function is ‘dropped’.

Now the next thing is to have the component render again after the button code has completed.

1 Like

Forcing rerender can be managed by using useState().