React frontend crashes when passing Config variables to resolver

Hi there,

I’m refactoring a plugin to use UI Kit 2. It parses a download link from a textfield given by the user, fetches the response, formats it and embeds it into the confluence page.

Frontend js:

import React, { Fragment, useEffect, useState } from 'react';
import ForgeReconciler, { Label, Text, useConfig, SectionMessage, Textfield, Link } from '@forge/react';
import { invoke } from '@forge/bridge';

const App = () => {
  const [htmlValue, sethtmlValue] = useState({ body: '', status: '' });
  const config = useConfig();
  if (!config) {
    return (
      <SectionMessage title="You need to configure this macro" appearance="warning">
        <Text>
          While editing the page, select the macro, and click on the pencil icon
          to display configuration options.
        </Text>
      </SectionMessage>
    );
  }
  console.log("Config: ", config?.path);
  const url_config = config?.path;
  console.log("Url config: ", url_config);


  useEffect(() => {
    console.log("✅ Passing path to invoke:", { path: url_config }); 
    invoke('fetch', { path: url_config })
      .then((response) => {
        console.log("Response: ", response);
        sethtmlValue({ body: response.body, status: response.status });
      });
  }, []);
  console.log(htmlValue.body);
  console.log(htmlValue.status);

  if (htmlValue.status != 200)
    return (
      <Text>n/a</Text>
    )
  if(htmlValue?.body) {
    var buildNumber;
    const buildNumberRe = /<p>(\d+)<\/p>/.exec(htmlValue.body);
    if (buildNumberRe != null)
      buildNumber = <Text>{buildNumberRe[1]}</Text>;
    const hashRe = /<p><small>(\w+)<\/small><\/p>/.exec(htmlValue.body);
    var hash;
    if (hashRe != null)
      hash = <Text>{hashRe[1]}</Text>;
    return (
      <Text>
        <Fragment>
        {buildNumber ? buildNumber : "Loading..."}
        {hash ? hash : "Loading..."}
        </Fragment>
      </Text>
    );
  };
  
  };


const ConfigEmbed = () => {
  return (
    <>
      <Label>Path to file in bucket</Label>
      <Textfield name="path" />
    </>
  );
};

ForgeReconciler.addConfig(<ConfigEmbed />);
ForgeReconciler.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

Backend resolver:

import Resolver from '@forge/resolver';
import { fetch } from '@forge/api';

const resolver = new Resolver();

resolver.define('fetch', async (req) => {
  try {
    const prefix = "https://supersecret.url";
    const path = await req.payload.path;
    console.log(path);
    const secret = process.env.SECRET;
    const url = prefix + path + "?" + secret;
    const result = await fetch(url);
    console.log('Fetch result:', result);
    const body = await result.text();
    const status = result.status;
    console.log('Body: ', body);
    console.log('Status: ', status);
    return { body, status };
  } catch (error) {
    console.error('Error in fetch:', error);
    throw error; // Re-throw to propagate the error
  }
});

export const handler = resolver.getDefinitions();

If I harcode the given path to url_config, it works and it fetches the url correctly.
When I add the Config textbox to the code, it crashes at the useEffect function with this error: Minified React error #310 – React
console.log shows the correct url_config variable right before crashing.

Any ideas what I’m doing wrong?

Thanks for the help in advance!

Hi dmSmil,

can you provide the full error detail, so it’s easier to diagnose what happens?

Inside your App component, the callback in your useEffect() hook depends on url_config, but it’s no listed as a dependency in the array. I recommend to add this, as this value might change between renders.

Cheers,
Jonathan

Use something like cursor.com and paste in the react error. It’ll restructure your code.

The issue is likely that the useEffect() needs to be above the if (!config) return {}