skip to Main Content

I am facing the issue that when I successfully submit my value then I set the value to empty, but it remains the same, console says it is empty but it’s not in components.

I think it’s a rendering issue because I am using separate component for input, I am using useState hook.

Input component:

import { useState } from "react";

const Input = (props) => {
  const [inn, setinn] = useState("")

  return (
    <div className="flex w-full p-5 justify-center items-center mx-auto gap-4 ">
      {props.title
        ? (
          <label for="helper-text" class={`block mb-1  w-[10%] text-xl text-gray-900 dark:text-white gap-5 ${props.classes}`}>
            {props.title}
          </label>
        ) : ("")
      }

      <input
        onChange={props.fn}
        type={props.type}
        id="helper-text"
        chk={props.chk} 
        aria-describedby="helper-text-explanation"
        class={`bg-gray-50 border border-gray-300 w-[50%] text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500 ${props.classes}`}
        placeholder={`Enter Your Valid ${props.name}`}
      />
    </div>
  )
}

export default Input;

Parent component:

import React, { useEffect, useState } from 'react'
import Button from '../../components/Button'
import Input from '../../components/Input'
import toast from 'react-hot-toast'

const AddTask = () => {
  const [inputs, setInputs] = useState({ content: "" })

  const dataSubmit = async (data) => {
    console.log(data)

    try {
      if (data.content.trim() === "") {
        toast.error("Please Enter a Valid Task")
      } else { 
        const res = await fetch(
          "http://localhost:3000/api/v1/users/add-todo",
          {
            method: "POST",
            headers: {
              "Content-Type": "application/json"
            },
            body: JSON.stringify(data),
            credentials: "include"
          }
        )
        const response = await res.json()
        console.log(response)
        if (response.statusCode === 200) {
          toast.success("Task Added Successfully")
          //   setInputs({content:e.target.value})
          setInputs({ content: "" })
        } else {
          toast.error(`Something Went Wrong : ${response.message}`)
        }
        setInputs({ ...inputs, content: "" })
      }
    } catch (error) {
      console.log("Error : ",error)
      toast.error(`Something Went Wrong: ${error}`)
    }
  }

  useEffect(() => { 
    if (inputs.content.trim() === "") {
      setInputs({content:""})
    }
  } , [inputs.content])

  return (
    <div>
      <form className="w-[60%] mt-20  mx-auto flex justify-center item center flex-col">
        <div>
          <h1 className="text-3xl text-center font-bold mb-5">Add Task</h1>
        </div>

        <Input
          classes='w-full h-12 m-[0px]'
          name="click here to write task"
          type="text"
          chk={inputs}
          fn={(e) => {
            setInputs({ content: e.target.value })
          }}
        />
    
        <Button
          fn={(e) => {
            e.preventDefault()
            dataSubmit(inputs)
          }}
          title="Add Task"
          classes="hover:bg-green-400 bg-zinc-600 flex text-center justify-center mt-5 mx-auto h-12 w-24"
        />
      </form>
    </div>
  )
}

export default AddTask

enter image description here

2

Answers


  1. in your Input component you need to catch updated input value using useEffect

    useEffect(() => {setInn(props.chk)}, [props.chk]);
    

    and pass inn to input value instead of props.chk

    Login or Signup to reply.
  2. You have a "semi-controlled" form input, in that it has the onChange handler, but the issue is that there is nothing setting the input’s value, e.g. it really isn’t controlled at all.

    Generally speaking, in React we typically use fully controlled form inputs, or we use fully uncontrolled form inputs.

    • Controlled: Uses React state to hold the "source of truth", and passes value and onChange props to an input. The state is referenced when working with form data
    • Uncontrolled: No state, add passes a defaultValue (or defaultChecked) prop and uses the form’s onSubmit event object to access the form fields’ values.

    It is because the Input component isn’t fully controlled that the input element still shows what was entered by the user.

    It is also a bit of a React anti-pattern to duplicate passed props into local state, the Input component’s inn state is unnecessary and should be removed.

    const Input = ({ classes, name, onChange, title, type, value }) => {
      return (
        <div className="fle ... ap-4 ">
          {!!title && (
            <label
              for="helper-text"
              class={`blo... ${classes}`}
            >
              {title}
            </label>
          )}    
    
          <input
            aria-describedby="helper-text-explanation"
            class={`bg-gr...  ${classes}`}
            id="helper-text"
            placeholder={`Enter Your Valid ${name}`}
            type={type}
            onChange={onChange} // <-- onChange handler
            value={value}       // <-- current input value
          />
        </div>
      );
    };
    

    AddTask: Update the Input component rendering to pass the appropriate props.

    <Input
      classes='w-full h-12 m-[0px]'
      name="click here to write task"
      type="text"
      value={inputs.content}      // <-- pass current input value
      onChange={(e) => {          // <-- pass change handler
        setInputs(inputs => ({
          ...inputs,              // <-- shallow copy existing state
          content: e.target.value // <-- set the content state value
        }));
      }}
    />
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search