#Where am I overwriting my inputs?

46 messages · Page 1 of 1 (latest)

fierce rover
#

It seems I'm overwriting inputs somewhere and I can't see what I've done wrong

I'm using this to update formData based on inputs chosen by the user

const useCharacterForm = () => {
  const [formData, setFormData] = useState<CharacterData>({});
  
  const handleInputChange = (
    name: string, 
    value: string | number | undefined
  ) => {
    setFormData((prevData) => {
      const updatedData = {
        ...prevData,
        [name]: value,
      };
      return updatedData;
    });
  };

  return {
    formData,
    handleInputChange,
  };
};
#

I'm using a switch statement to determine which sort of input is needed for each section, and then designing the inputs based on what sort of input is expected

        case 'background':
            return (
                <React.Fragment key={uniqueKey}> 
                    <div>                      
                        <input  type={props.inputType} 
                                className={baseClassStyle}
                                name={props.sectionName}
                                value={choice}
                                checked={formData[props.sectionName] === choice}
                                onChange={(e) => handleInputChange(props.sectionName, e.target.value)}
                        /> 

                        <label className='m-2'>
                            {choice}
                        </label> 
                    </div> 
                </React.Fragment>
            )
        
        case 'levels':
            return (
                <React.Fragment key={uniqueKey}> 
                    <div className='flex items-stretch pt'> 
                        <label className='mr-16 w-4'>
                            {choice}
                        </label> 
                        
                        <input  type={props.inputType} 
                                className={`${baseClassStyle} `}
                                name={choice} 
                                value={formData[choice] || ''} 
                                min="0"
                                max="20"
                                onChange={(e) => handleInputChange(choice, e.target.value)}
                        /> 

I think these are all fine, but this is how the inputs are created. I think the issue is somewhere in handleInputChange, but I'm really at a loss for a solution

north relic
#

you don't seem to be updating choice?

#

oh that's a checkbox?

fierce rover
north relic
#

yeah if it wasn't a checkbox it'd be an issue since you're setting value={choice}

#

and the second one is what, a number/range?

fierce rover
# north relic yeah if it wasn't a checkbox it'd be an issue since you're setting `value={choic...

value is what's sent by selecting an input, and that data is what should be getting to formData

When I do console.log(formData), I can see the values being applied within handleInputChange, but they seem to get erased somehow. They seem to be getting erased when making changes to a new section. Switching inputs within levels works fine, but if I then go to the "background" section and make an input, formData returns to blank and all input for levels are lost

The second case is a number input

#

Also, am a beginner, so it's very likely something really dumb or simple I'm missing

north relic
#

are you perhaps getting a new instance of the component?

fierce rover
#

Unless you're talking about something other than formData

dusk glen
#

If you can make an example that reproduces the issue that would be helpful

fierce rover
dusk glen
#

Yeah, whatever the smallest bit that reproduces the issue you're seeing is.

#

It's just kinda hard to debug these behaviors with just limited sections of the code to look at.

fierce rover
fierce rover
# dusk glen Yeah, whatever the smallest bit that reproduces the issue you're seeing is.

I got things simplified a ton. I can't imagine being able to remove much else to keep this functioning and leading to my issue. There's 4 files represented here:

  • app: displays all components (just one now)
  • menu-builder: creates props for each menu section of the accordion
  • accordion: a template for building out accordion options based on props from above
  • form-processing: takes inputs from accordion and should create an object to store everything

https://pastebin.com/Sm2ESswR

#

And here's what's happening:

#

I put in values for fields "a" and "b", and they both get updated. But then I put in values for "1" and "2", and they get updated, but the a & b values vanish

north relic
#

those seem like fully separate components

#

if you try the first one again, do you get the form with a & b without 1 & 2 ?

dusk glen
fierce rover
north relic
#

do you get a & b back or not?

#

if you do, there's no resetting going on, you're just looking at different formData instances

fierce rover
fierce rover
north relic
#

you have multiple of the component that calls useCharacterForm, so you have multiple separate formDatas

#

if you want to make them share the formData, you have to move useCharacterForm to a shared scope, so it's only instantiated once

fierce rover
#

I see I'm calling it here

// menu-builder
const MenuBuilder = () => {  
  const {formData} = useCharacterForm();

  useEffect(() => {
    console.log('formData updated in MenuBuilder:', formData);
  }, [formData]);

and here

//accordion 
const Accordion = (props: AccordionProps) => {
    const contentRef = useRef<HTMLDivElement>(null);
    const {formData, handleInputChange} = useCharacterForm();

The call in menu-builder, I thought, was just going to allow me to see how formData was looking at that point. Is removing that all that's needed to keep formData from being instantiated again?

dusk glen
#

Yeah, you call useCharacterForm it calls useState which creates a brand new state.

fierce rover
#

With this, just accessing formData elsewhere won't be creating a new instance, right?

const useCharacterForm = () => {
  const [formData, setFormData] = useState<CharacterData>({});

I'm not using useCharacterForm anywhere else, but I'm trying to use formData to get input from users. That should be fine to do, no?

north relic
#

even if you're using it in one place, you might be calling it multiple times

#
function FormComponent() {
  const [formData] = useCharacterForm();
  return <>{JSON.stringify(formData, null, 2)}</>
}

function Container() {
  return (
    <>
      <FormComponent />
      <FormComponent />
    </>
  );
}
``` if you only have 1 `Container`, that's 2 separate `FormComponent`s, which have their own, separate `formData`s
fierce rover
# north relic ```tsx function FormComponent() { const [formData] = useCharacterForm(); ret...

That's a very good point and insight. useCharacterForm is defined outside of any other functions, and it's not nested in anything, so it doesn't appear that this is going on (but it might be).

Looking at your example, I'd check to see if any parents of the function are called, and I'm not seeing that in my code, but are there any other indicators that this might be going on?

Is this certainly what's happening somewhere? Is calling useState multiple times the only way I could be instantiating new formData ?

north relic
#

this is almost definitely what's happening

north relic
# fierce rover I got things simplified a ton. I can't imagine being able to remove much else to...

in this example, you have useCharacterForm in Accordion, and you call Accordion twice in MenuBuilder
because useCharacterForm is scoped to Accordion, each instance of that component has its own formData

MenuBuilder has its own useCharacterForm, but you aren't passing that to either Accordion, so it doesn't have any effect.
you'd need to remove useCharacterForm from Accordion, and use formData/handleInputChange passed from MenuBuilder, so each MenuBuilder (of which you have one) has a single state that's shared between its children Accordions

#

(in the example, you have 3 separate states, the one in MenuBuilder is never modified because its handleInputChange is never called)

fierce rover
fierce rover