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
2
Answers
in your Input component you need to catch updated input value using useEffect
and pass inn to input value instead of props.chk
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.
value
andonChange
props to an input. The state is referenced when working with form datadefaultValue
(ordefaultChecked
) prop and uses the form’sonSubmit
event object to access the form fields’ values.It is because the
Input
component isn’t fully controlled that theinput
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’sinn
state is unnecessary and should be removed.AddTask: Update the
Input
component rendering to pass the appropriate props.