Home > database >  State hook variable not updated inside functional component
State hook variable not updated inside functional component

Time:10-17

Upon updating the name of an ingredient, I want to submit this data is an ingredient with the up-to-date name: from "Milk" to "Cow's milk".

I've provided simple "1,2,3" steps as comments to briefly illustrate the flow of things, but you can assume that the console logged values you see here all happen right after I press the submit button (FloatingButtons):

export const Ingredient = ({
    ingredient: ingredientProp,
  }: IngredientProps) => {
    const [name, setName] = useState(ingredientProp.name);
    // Prints expected updated name: "Cow's milk"
    console.log("name", name);
    const [ingredient, setIngredient] = useState(ingredientProp);
    // Prints expected updated ingredient containing the name: "Cow's milk"
    console.log("ingredient", ingredient);
  
    useEffect(() => {
        // 2. Replace ingredient name with newName
        // Prints expected updated name: "Cow's milk"
      const newName = name;
      console.log("newName", newName);
      setIngredient({ ...ingredient, name: newName });
    }, [name]);
  
  
    return (
      <form
        className="Ingredient"
        id={ingredientProp.id}
        onSubmit={(e) => {
          e.preventDefault();
          console.log(ingredient);
          // 3. Submit updated ingredient
          // Prints ingredient with outdated name ("Milk"), why?
          submitData(ingredient);
        }}
      >
        <EditableField
          defaultValue={name}
          onChange={(newName) => {
            console.log("newName", newName)
            //1. Set name to newName
            // Prints "Cow's milk", check!
            setName(newName);
          }}
        />
        {/* Is a submit button that refers to the parent form */}
        <FloatingButtons
          formId={ingredientProp.id}
        />
      </form>
    );
  };

CodePudding user response:

I would think that you need to refactor your code a little bit Create a handleSubmit function and wrap it around a useCallback hook

...
const handleSubmit = useCallback(() => {
   submitData(ingredient);
}, [ingredient])
...
return <form
onSubmit={handleSubmit}
>
...
</form>

That's one way to do it, but you could also remove setIngredient since only name property will be changing; And that should give you the following

 export const Ingredient = ({
    ingredient: ingredientProp,
  }: IngredientProps) => {
    const [name, setName] = useState(ingredientProp.name);
  
  const handleSubmit = useCallback(() => {
     submitData({
        ...ingredient,
        name,
      });
  }, [name])
  
    return (
      <form
        className="Ingredient"
        id={ingredientProp.id}
        onSubmit={handleSubmit}
      >
       ...
      </form>
    );
  };

CodePudding user response:

Thank you for your refactoring suggestion, that certainly helps but I did some more digging and realized the underlying issue was that there was more than one form with the same form id and that was somehow messing with the onSubmit event. I've now made sure that every form and its corresponding submit button have more specific ids.

  • Related