Home > Mobile >  I use handleChange to set the state value, but it not change
I use handleChange to set the state value, but it not change

Time:10-25

I want to create responsive multiple forms (form1, form2, and form3) with the same pages using framer motion. However, when I create the state value and want to make it change when the user fills the form by using setValue in handleChange, the value of the state is not updated correctly as I want. When the user fills Select Protocol the filled form is not updated on the user screen but the state is changed. Moreover, when the user fills Select number of hops after that, the link level state is deleted. I have no idea how to fix this problem.

import React, { useState, useEffect } from "react";
import { motion, AnimatePresence } from "framer-motion";

export default function ExperC() {

  // state that I want to collect user fill form
  const [value, setValue] = useState({
    link_level: "",
    hop_select: "",
    num_hop: "",
    location_1: "",
    location_2: "",
    photon_loss: "",
    dep: "",
    gate_error: "",
    coherent: "",
    mea_error: "",
    trajectory: "",
  });

  const handleChangeLinklevel = (e) => {
    setValue({ ...value, link_level: e.target.value });
  };
  const handleChangeHop = (e) => {
    setValue({ ...value, hop_select: e.target.value });
  };

  // jsx of form 1
  const form1 = (
    <form action="" className="w-[140%]">
      <div className="flex space-x-2">
        <h1 className="text-[#fff] text-4xl">Configure your </h1>
        <h1 className="text-[#ad73f1] text-4xl">Qwanta network</h1>
      </div>

      <p className="mt-5 mb-2 text-gray-400">Select Protocol</p>
      <select
        className="w-full h-8 text-black bg-white"
        onChange={handleChangeLinklevel}
        value={value.link_level}
      >
        <option value="" disabled selected>
          Select your protocol
        </option>
        <option value="0G">0 Generation (0G)</option>
        <option value="1G">1G-Ss-Dp (1G)</option>
        <option value="2G-NCX">2G-NonLocal-CNOT (2G-NCX)</option>
        <option value="HG-DE">1-2G-Directed-Encoded, (HG-DE)</option>
        <option value="HG-E2E-PE">HG-E2E-PurifiedEncoded</option>
        <option value="Design own protocol">Design own protocol</option>
      </select>

      {useEffect(() => {
        console.log("test", value);
      })}

      <p className="mt-5 mb-2 text-gray-400">Select number of hops</p>
      <select
        className="w-full h-8 text-black bg-white"
        onChange={handleChangeHop}
        value={value.hop_select}
      >
        <option value="" disabled selected>
          2^n hops
        </option>
        <option value="2">2 hops, 3 nodes</option>
        <option value="4">4 hops, 5 nodes</option>
        <option value="8">8 hops, 9 nodes</option>
      </select>
    </form>
  );

  const form2 = <>This is form 2</>

  const form3 = <>This is form 3</>;

  // for responsive slide between form using framer motion
  const experitem = [
    { name: "config1", icon: "test1", form: form1 },
    { name: "config2", icon: "test2", form: form2 },
    { name: "config3", icon: "test3", form: form3 },
  ];

  const [selectedTab, setSelectedTab] = useState(experitem[0]);

  return (
    <div className="flex flex-col w-[800px] h-[600px] absolute top-[150px] bg-[#262626] left-1/3 rounded-xl overflow-hidden">
      <nav className="bg-gray1 pt-3 px-3 rounded-t-xl h-[60px]">
        <ul className="flex w-full">
          {experitem.map((item, index) => (
            <motion.li
              key={index}
              className={`text-white list-none cursor-pointer rounded-t-xl w-full p-3 relative bg-[#262626] h-[70px] flex justify-between align-middle flex-1 min-w-0
            `}
              onClick={() => setSelectedTab(item)}
              initial={{ y: 0 }}
              whileHover={{ y: -5 }}
            >
              {item.name}
              {/* {item == selectedTab ? (
                <div className="absolute -bottom-[2px] left-0 right-0 h-[1px] bg-blue-500" />
              ) : null} */}
            </motion.li>
          ))}
        </ul>
      </nav>

      <main className="bg-[#262626] flex justify-left align-middle flex-grow mt-6 ml-5">
        <AnimatePresence exitBeforeEnter>
          <motion.div
            key={selectedTab ? selectedTab.name : "empty"}
            initial={{ x: -100, opacity: 0 }}
            animate={{ x: 0, opacity: 1 }}
            exit={{ x: -10, opacity: 0 }}
            transition={{ duration: 0.2 }}
          >
            {selectedTab ? selectedTab.form : null}
          </motion.div>
        </AnimatePresence>
      </main>
    </div>
  );
}

enter image description here

enter image description here

CodePudding user response:

The problem here is That your defining your form in const once they are in this const form1, the value is saved as its value at the moment of declaration, not by ref hence it will change and you can't see it since inside the const link_level is still empty string and this also explains why when you pick from the second the value reset because

 setValue({ ...value, hop_select: e.target.value });

will take the value in form1 which was empty string To solve this simply create a react component for each form this will solve it here is a link to a simple edit https://codesandbox.io/s/jolly-aryabhata-jffddt?file=/src/App.js

CodePudding user response:

If you don't directly reference your forms in experitem, but rather assign an id and render the forms based on that id, then you can avoid it being reset. But it's probably best to just create separate components for the forms.

// Use an ID here instead of the element itself
const experitem = [
    { name: "config1", icon: "test1", formId: 0 },
    { name: "config2", icon: "test2", formId: 1 },
    { name: "config3", icon: "test3", formId: 2 },
];

// This state determines which formId to use
const [selectedTab, setSelectedTab] = useState(0);

<ul className="flex w-full">
    {experitem.map((item, index) => (
        <li
          key={index}
          // Set the state to the id of the form you want to see
          onClick={() => setSelectedTab(item.formId)}
        >
          {item.name}
        </li>
    ))}
</ul>
// Render the forms based on that id
{selectedTab === 0 ? form1 : selectedTab === 1 ? form2 : form3}

  • Related