reactjsshadcnui

useState not retaining the values while using the same common form for register and login using selective rendering


I am trying to use a common form component for the Register and Login section, I am using Tabs (register and login). when I store data "name" in the register state and then switch the tab to login and then come back then the registered state variable is wiped clean.

Should I just write 2 different forms or is there a better way to write it?

import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { useState } from "react";

const RegisterAndLoginForm = ({name}) => {
  const [registerForm, setRegisterForm] = useState({name:""});
  const [loginForm, setLoginForm] = useState({});

  const handleRegisterInput = (e) =>{
    setRegisterForm({...registerForm, [e.target.name]: e.target.value});
  }

  console.log("reg->",registerForm);

  const handleLoginInput = (e) =>{
    setLoginForm({...loginForm, [e.target.name]: e.target.value})
  }
  
  const handleSubmit = (e) =>{
    e.preventDefault();
  }

  const clearForm = () =>{

  }

  const convertToBase64 = (e) => {
    const file = e.target.files[0];
    const reader = new FileReader();
    reader.readAsDataURL(file);

    reader.onload = () => {
      setRegisterForm({ ...registerForm, avatar: reader.result });
    };
  };

  return (
    <main className="bg-transparent_bg w-full flex flex-col items-center box-border rounded-md">
      <form
        className="w-full text-center space-y-3 p-2 box-border"
        onSubmit={handleSubmit}
      >
        <h3 className="font-extrabold text-foreground text-xl bg-slate-500 py-2 rounded-md tracking-widest">
          {name}
        </h3>
        {name === "Register" && (<label htmlFor="name">Name :</label>)}
        {name === "Register" && (<input
          id="name"
          className="input"
          type="text"
          placeholder="name"
          name="name"
          value={registerForm?.name}
          onChange={(e)=>handleRegisterInput(e)}
        />)}
        <label htmlFor="username">Username: </label>
        <input
          id="username"
          className="input"
          type="text"
          placeholder="username"
          name="username"
          // value={postData.title}
          onChange={name === "Register" ? handleRegisterInput : handleLoginInput}
        />
        {name === "Register" && (<label htmlFor="email">Email: </label>)}
        {name === "Register" && (<input
          id="email"
          className="input"
          type="text"
          placeholder="username"
          name="username"
          // value={registerForm?.title}
          onChange={handleRegisterInput}
        />)}
        <label htmlFor="password">Password: </label>
        <input
          id="password"
          className="input"
          type="password"
          placeholder="password"
          name="password"
          // value={postData.title}
          onChange={name === "Register" ? handleRegisterInput : handleLoginInput}
        />
        {name === "Register" && (<label htmlFor="confirmPassword">Confirm password: </label>)}
        {name === "Register" && (<input
          id="confirmPassword"
          className="input"
          type="password"
          placeholder="confirm assword"
          name="confirmPassword"
          // value={postData.title}
          onChange={handleRegisterInput}
        />)}

        {name === "Register" && (<div className="w-full bg-slate-500 text-foreground py-2 px-1 rounded-md overflow-hidden">
          <input
            className="text-[12px] font-medium cursor-pointer"
            type="file"
            onChange={convertToBase64}
          />
        </div>)}

        <div className="flex justify-center gap-5 py-1 box-border">
          <button
            type="submit"
            className="bg-blue-400 w-24 px-3 py-2 rounded-md hover:bg-blue-500 active:bg-blue-600 text-white tracking-widest"
          >
            {name}
          </button>
          <button
            onClick={clearForm}
            type="button"
            className="bg-red-500 w-24 px-3 py-2 rounded-md hover:bg-red-600 active:bg-red-700 text-white tracking-widest"
          >
            Clear
          </button>
        </div>
      </form>
    </main>
  );
};

const LoginAndRegister = () => {
  return (
    <div className="grid m-auto grid-cols-2">
      <div>
        <Tabs defaultValue="register" className="w-[500px] p-1">
          <TabsList className="w-full">
            <TabsTrigger value="register" className="w-[50%]">
              Register
            </TabsTrigger>
            <TabsTrigger value="login" className="w-[50%]">
              Login
            </TabsTrigger>
          </TabsList>
          <TabsContent value="register" className="border rounded-md">
            <RegisterAndLoginForm name={"Register"} />
          </TabsContent>
          <TabsContent value="login" className="border rounded-md">
            <RegisterAndLoginForm name={"Login"} />
          </TabsContent>
        </Tabs>
      </div>
      <div>memories logo</div>
    </div>
  );
};

export default LoginAndRegister;

enter image description here


Solution

  • You can try using the context API so that you can refer to, for example, the register form data.

    /* ... */
    import { createContext, useState, useContext } from "react";
    
    const RegisterFormContext = createContext(null);
    
    const RegisterAndLoginForm = ({name, setRegisterForm}) => {
      const registerForm = useContext(RegisterFormContext);
      /* ... */
    };
    
    const LoginAndRegister = () => {
      const [registerForm, setRegisterForm] = useState({name: ""});
      return (
        <RegisterFormContext.Provider value={registerForm}>
          <div className="grid m-auto grid-cols-2">
            /* ... */
          </div>
        </RegisterFormContext.Provider>
      );
    };
    
    export default LoginAndRegister;
    

    As you can see, you'd need to pass the parent's setRegisterForm callback to the RegisterAndLoginForm component.


    As you've commented, contexts aren't necessary for this. They are more often used where a value stack is really necessary.