TextField not responding to state change

Using the example for TextField in the doco I should be able to manipulate the state e.g. setInputValue(value.toUpperCase()) but the TextField doesnt reflect the change. Also, the initial state value doesnt show in the TextField either, anyone know what am I missing here?

const App = () => {
  const [inputValue, setInputValue] = useState("initial")

  return (
    <TextField
      label="Name"
      name="name"
      value={inputValue}
      onChange={(value) => setInputValue(value)}
    />
  )
}

Hey @IanWorthington,

You tagged custom UI and UI Kit (beta) and ui-kit-2 in your post, which one are you using?

Using UI Kit 2, I modified frontend/index.jsx created as part of Forge Quest as follows:

import React, { useEffect, useState } from 'react';
import ForgeReconciler, { StatusLozenge, Text, TextField } from '@forge/react';
import { invoke, view } from '@forge/bridge';

const App = () => {
  const [data, setData] = useState(null);
  const [theme, setTheme] = useState(null);
  const [inputValue, setInputValue] = useState("initial")

  useEffect(() => {
    const getTheme = async() => {
      const context = await view.getContext();
      console.log(context);
      console.log(context.theme.colorMode);
      setTheme(context.theme.colorMode);
    }

    getTheme();
  }, []);

  useEffect(() => {
    invoke('getText', { example: 'my-invoke-variable' }).then(setData);
  }, []);

  return (
    <>
      <Text>Hello world!</Text>
      <Text>{data ? data : 'Loading...'}</Text>
      <Text>Current theme: <StatusLozenge>{theme ? theme : 'Loading...'}</StatusLozenge></Text>
      <TextField label="Name" name="name" value={inputValue} onChange={(value) => setInputValue(value.toUpperCase())}></TextField>

    </>
  );
};

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

And this renders ‘initial’ in the Text Field as expected, and then when the text field is changed renders the text as uppercase. Is that not what you’re after? If you’re using UI Kit or Custom UI this may work a little differently so let me know

2 Likes

Hey @mpaisley UI Kit 2, I got carried away with the tagging :wink:

Thanks for your example, it looks exactly like what I’m doing so I will create a new project and report back. Glad to see it works for you!

Thanks again! Found the problem, if TextField is in a Form, everything breaks.

Is that expected or should Form support TextField?

(Not that its a big issue as I can access its value via state).

1 Like

Hey @IanWorthington,

The TextField value is only available outside a Form component. This changes what you can do somewhat. Here’s an example I created to demonstrate how you might get it to work:

import React, { useEffect, useState } from 'react';
import ForgeReconciler, { StatusLozenge, Text, TextField, Form } from '@forge/react';
import { invoke, view } from '@forge/bridge';

const App = () => {
  const [data, setData] = useState(null);
  const [theme, setTheme] = useState(null);
  const [inputValue, setInputValue] = useState("initial")
  const [formState, setFormState] = useState(undefined);


  useEffect(() => {
    const getTheme = async() => {
      const context = await view.getContext();
      console.log(context);
      console.log(context.theme.colorMode);
      setTheme(context.theme.colorMode);
    }

    getTheme();
  }, []);

  const onSubmit = (formData) => {
    /**
     * formData:
     * {
     *    name: 'text',
     * }
     */
    // These console logs appear in your browser console.
    console.log("from submit: " + formData.name.toUpperCase())
    console.log("from onChange: " + JSON.stringify(formData));
    setFormState(formData.name.toUpperCase());
  };

  useEffect(() => {
    invoke('getText', { example: 'my-invoke-variable' }).then(setData);
  }, []);

  return (
    <>
      <Form onSubmit={onSubmit}>
        <Text>Hello world!</Text>
        <Text>{data ? data : 'Loading...'}</Text>
        <Text>Current theme: <StatusLozenge>{theme ? theme : 'Loading...'}</StatusLozenge></Text>
        <TextField label="Name" name="name" defaultValue={inputValue} onChange={(formData) => setInputValue(formData.toUpperCase())}></TextField>
      </Form>
      {formState && <Text>This value is set onSubmit: {formState}</Text>}
      {inputValue && <Text>This value is set onChange: {inputValue}</Text>}
    </>
  );
};

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

Here’s what happens in my app:

1 Like

Yep, exactly the same as me, the initial state doesnt apply and the onchange state change doesnt apply. All good, I’ve ditched the Form and its working well. Thanks for the help!

Hi, @mpaisley,

Was your example working ?
I’m trying to get something similar to work but the onChange is not triggerring at all


          <Form onSubmit={handleSubmit(onSubmit)}>
            <FormSection>
              <Label labelFor={getFieldId("name")}>
                Name
                <RequiredAsterisk />
              </Label>
              <Textfield onChange={(e) => console.log("====>onchange",e)} placeholder="Enter a name" {...register("name", { required: true })} />
            </FormSection>
            <FormFooter>
              <Stack space='space.100'>
                <Button appearance="primary" type="submit">
                  Submit
                </Button>
              </Stack>
            </FormFooter>
          </Form>

The console.log never trigger, am I missing something?
I’m using UI kit 2.

And in my case I like the Form since it does the required validation and stuff.
Help :slight_smile: