Search code examples
reactjsformsreact-hooks

Why storing form data in useState() hook in React?


I am somewhat familiar with React.

In react tutorials, I have seen people creating useState hooks to store form data and also making them controlled and started doing the same but recently I saw a video of coder creating a form without using any useState for storing the data?

This has left me stumped because I am not understanding why I need to store form data in useState hook now. For what type of situations, is it useful to use state or just simply take the form value?

Please help.

I have tried searching google, reading some blogs on useState hooks, how it is used where we want to re-render a component.

Like, If I am displaying some data, and want to change it on some event, then I will use useState hook so that it will re-render the display component, with the updated state.

But I am still not understanding its use case with forms.


Solution

  • In a React form, you may want to do something on the screen as a user is typing using an onChange callback. You would need to store the user's input in state in order to properly deal with it in a useEffect. Just storing naked variables in components in React is terrible practice.

    You generally only use destructured constants or derived conditional variables after hooks are called in a component in order to affect the display or to pass hook results as input to other hooks.

    I would be interested to see the video or tutorial that showed you how to do a form "without state" in React because I'm not sure how that's possible - unless they were using a third-party library like formik which abstracts the useState away from you through it's own methods.

    *ADDED EXAMPLE

    Consider this simple comparison of two forms, one with state and one without:

    https://codesandbox.io/p/sandbox/zen-sammet-imfzl5

    app.tsx

    import { useState } from "react";
    import "./App.css";
    import FormWithState from "./FormWithState";
    import FormWithoutState from "./FormWithoutState";
    
    function App() {
      return (
        <>
          <div
            style={{
              border: "1px solid green",
              marginBottom: "1rem",
              padding: "1rem",
            }}
          >
            <div>
              This form with state notifies after 3 characters, and on submit.
            </div>
            <FormWithState />
          </div>
          <div style={{ border: "1px solid red", padding: "1rem" }}>
            <div>This form without state can't alert or useEffect</div>
            <FormWithoutState />
          </div>
        </>
      );
    }
    
    export default App;

    FormWithState.tsx

    import { useEffect, useState } from "react";
    import "./App.css";
    
    export default function FormWithState() {
      const [message, setMessage] = useState("");
    
      const onChange = (e: any) => {
        setMessage(e.target.value);
      };
    
      const onSubmit = (e: any) => {
        e.preventDefault();
        alert(`You sent the message: ${message}`);
      };
    
      useEffect(() => {
        if (message.length >= 3) {
          alert("This message is longer than 3 characters. Wow!");
        }
      }, [message]);
    
      return (
        <div className="App">
          <form onSubmit={onSubmit}>
            <input type="text" name="name" onChange={onChange} />
            <button type="submit">Submit</button>
          </form>
        </div>
      );
    }

    FormWithoutState.tsx

    import { useEffect } from "react";
    import "./App.css";
    
    export default function FormWithState() {
      let message = "";
    
      const onChange = (e: any) => {
        message = e.target.value;
      };
    
      const onSubmit = (e: any) => {
        e.preventDefault();
        alert(`You sent the message: ${message}`);
      };
    
      useEffect(() => {
        if (message.length > 3) {
          alert("This message is longer than 3 characters. Wow!");
        }
      }, [message]);
    
      return (
        <div className="App">
          <form onSubmit={onSubmit}>
            <input type="text" name="name" onChange={onChange} />
            <button type="submit">Submit</button>
          </form>
        </div>
      );
    }

    Notice how the green form can alert and useEffect as the user types / submits - while the red form cannot.

    Both Forms:

    enter image description here

    This works (with state): enter image description here

    This does not work (without state): enter image description here

    I hope that helps a bit!