how to conditionally render the respond from an api - javascript

I want to get input from a user and compare it with the response I am getting from API, and conditionally render the information if it match or just show a sorry message,(the API only contain 1 set of a data object including 4 value) let me know what am I missing.
here is my code
import React, { useState } from "react";
import axios from "axios";
function Form() {
const [vatInput, setVatInput] = useState("");
const [responseVatState, setResponseVatState] = useState("");
const [responseCountryCodeState, setResponseCountryCodeState] = useState("");
const [result, setResult] = useState(false);
const handelVatState = (event) => {
setVatInput(event.target.value);
};
const closeModalHandler = () => {
setResult(false);
};
const onFormSubmit = (event) => {
event.preventDefault();
axios
.get("Some URL")
.then((response) => {
setResponseVatState(response.data.response.data.VATNumber);
setResponseCountryCodeState(response.data.CountryCode);
})
.catch((error) => {
console.log(error);
});
};
const inputCountryCode = vatInput.substring(0, 2);
const inputVatCode = vatInput.substring(2);
if (
inputCountryCode === responseCountryCodeState &&
inputVatCode === responseVatState
) {
setResult(true);
} else {
setResult(false);
}
return (
<div >
<h4>VAT Validator</h4>
<form onSubmit={onFormSubmit}>
<label className="text-muted">Please Enter A Vat Number:</label>
<input
type="text"
name="VatInput"
placeholder="Please Enter A Vat Number"
onChange={handelVatState}
/>
<br />
<input type="submit" value="Let'Go" />
</form>
<label className="text-muted">Result : </label>
{result ? (
<div>{vatInput}</div>
) : (
<div clicked={closeModalHandler}>
<span> Sorry !!! Please Insert corect VAT Number</span>
</div>
)}
</div>
);
}
export default Form;
and the error is
react-dom.development.js:14997 Uncaught Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.
so I get the input from the user and set it with hooks, then with Axios call get my data, then I split the string with
const inputCountryCode = vatInput.substring(0, 2);
const inputVatCode = vatInput.substring(2);
to compare with the input I have, if it's the same then render the data if not just render the sorry message

You have a couple of issues, the main of which resulting in Uncaught Error: Too many re-renders. React limits the number of renders to prevent an infinite loop. is due to an infinite loop of component re-rendering, which you force by setting state directly in the function body.
More specifically, this code:
if (
inputCountryCode === responseCountryCodeState &&
inputVatCode === responseVatState
) {
setResult(true);
} else {
setResult(false);
}
force react to re-evaluate the component because you're changing its state by using setResult. When react starts rendering the new body it yet again encounters setResult which results in a new update and re-render which, as you see, leads to a never-ending loop.
Furthermore, you don't need to save the request response to the component state at all, as it is relevant just for the calculation, which is needed only in the form submit handler itself. So, you should ditch the
const [responseVatState, setResponseVatState] = useState("");
const [responseCountryCodeState, setResponseCountryCodeState] = useState("");
state variables altogether. The only state you need except the input value is the validation result.
Also, you have a typo: setResponseVatState(response.data.response.data.VATNumber); should be setResponseVatState(response.data.VATNumber);.
Try this:
import React, { useState } from "react";
import axios from "axios";
function Form() {
const [vatValue, setVatValue] = useState("");
const [isVatValid, setIsVatValid] = useState(false);
const handelVatState = (event) => {
setVatValue(event.target.value);
};
const closeModalHandler = () => {
setIsVatValid(false);
};
const onFormSubmit = (event) => {
event.preventDefault();
axios
.get("[URL]")
.then((response) => {
const inputCountryCode = vatValue.substring(0, 2);
const inputVatCode = vatValue.substring(2);
const { VATNumber, CountryCode } = response.data;
if (inputCountryCode === CountryCode && inputVatCode === VATNumber) {
setIsVatValid(true);
}
else {
setIsVatValid(false);
}
})
.catch((error) => {
console.log(error);
});
};
return (
<div >
<h4>VAT Validator</h4>
<form onSubmit={onFormSubmit}>
<label className="text-muted">Please Enter A Vat Number:</label>
<input
type="text"
name="VatInput"
placeholder="Please Enter A Vat Number"
onChange={handelVatState}
/>
<br />
<input type="submit" value="Let'Go" />
</form>
<label className="text-muted">Result : </label>
{isVatValid ? (
<div>{vatValue}</div>
) : (
<div clicked={closeModalHandler}>
<span> Sorry !!! Please Insert corect VAT Number</span>
</div>
)}
</div>
);
}
export default Form;
Also, I suppose <div clicked={closeModalHandler}> should be <div onClick={closeModalHandler}>?
EDIT:
Here is your solution after comments:
import React, { useState } from "react";
import axios from "axios";
function Form() {
const [vatValue, setVatValue] = useState("");
const [isVatValid, setIsVatValid] = useState(null);
const handelVatState = (event) => {
setVatValue(event.target.value);
};
const closeModalHandler = () => {
setIsVatValid(null);
};
const onFormSubmit = (event) => {
event.preventDefault();
axios
.get("https://vat.erply.com/numbers?vatNumber=BG999999999")
.then((response) => {
const inputCountryCode = vatValue.substring(0, 2);
const inputVatCode = vatValue.substring(2);
const { VATNumber, CountryCode } = response.data;
if (inputCountryCode === CountryCode && inputVatCode === VATNumber) {
setIsVatValid(true);
}
else {
setIsVatValid(false);
}
})
.catch((error) => {
console.log(error);
});
};
const getResultRepresentation = () => {
if (isVatValid === null) {
return null;
}
if (isVatValid) {
return (
<>
<label className="text-muted">Result: </label>
<div>{vatValue}</div>
</>
);
}
else {
return (
<div onClick={closeModalHandler}>
<span> Sorry !!! Please Insert corect VAT Number</span>
</div>
);
}
}
return (
<div >
<h4>VAT Validator</h4>
<form onSubmit={onFormSubmit}>
<label className="text-muted">Please Enter A Vat Number:</label>
<input
type="text"
name="VatInput"
placeholder="Please Enter A Vat Number"
value={vatValue} // <= missing
onChange={handelVatState}
/>
<br />
<input type="submit" value="Let'Go" />
</form>
{getResultRepresentation()}
</div>
);
}
export default Form;
And here is a CodeSandbox to test it out.

Related

How to validate input[type="date] in React?

There is a component:
import React, { useEffect, useState } from "react";
import { useParams } from "react-router";
import { NavLink } from "react-router-dom";
const EditIntern = () => {
const { id } = useParams();
const [intern, setIntern] = useState([]);
const [name, inputName] = useState("");
const [email, inputEmail] = useState("");
const [start, inputStart] = useState("");
const [end, inputEnd] = useState("");
const [errorNameEmpty, isErrorNameEmpty] = useState(true);
const [errorEmailEmpty, isErrorEmailEmpty] = useState(true);
const [errorEmailValid, iserrorEmailValid] = useState(false);
const [errorStartEmpty, isErrorStartEmpty] = useState(true);
const [errorEndEmpty, isErrorEndEmpty] = useState(true);
const validEmail = new RegExp(
/(\w+([-+.']\w+)*#\w+([-.]\w+)*\.\w+([-.]\w+)*)/gm
);
const dateValidate = () => {
if (start.value > end.value) {
console.log("Start > end");
console.log(start.valueAsNumber);
console.log(end.valueAsNumber);
} else {
console.log("Ok");
console.log(start.valueAsNumber);
console.log(end.valueAsNumber);
}
};
useEffect(() => {
const fetchIntern = async () => {
const response = await fetch(`http://localhost:3001/interns/${id}`);
const intern = await response.json();
setIntern(intern);
};
fetchIntern();
console.log(`I want to get intern with id: ${id}!`);
}, [id]);
return (
<div>
<NavLink to="/">Back to list </NavLink>
<form>
<label>Name</label>
<input
type="text"
name="name"
value={name}
onChange={(e) => {
if (e.target.value === "") {
isErrorNameEmpty(true);
} else {
isErrorNameEmpty(false);
}
inputName(e.target.value);
}}
onClick={(e) => {
if (e.target.value === "") {
isErrorNameEmpty(true);
}
}}
/>
{errorNameEmpty ? <span>Name can't be empty</span> : <></>}
<label>Email</label>
<input
type="text"
name="email"
value={email}
onChange={(e) => {
if (e.target.value === "") {
isErrorEmailEmpty(true);
} else if (!validEmail.test(e.target.value)) {
iserrorEmailValid(true);
isErrorEmailEmpty(false);
} else {
iserrorEmailValid(false);
isErrorEmailEmpty(false);
}
inputEmail(e.target.value);
}}
onClick={(e) => {
if (e.target.value === "") {
isErrorEmailEmpty(true);
}
}}
/>
{errorEmailEmpty ? <span>Email can't be empty</span> : <></>}
{errorEmailValid ? <span>Example: email#gmail.com</span> : <></>}
<label>Start date</label>
<input
type="date"
name="email"
value={start}
onChange={(e) => {
if (e.target.value === "") {
isErrorStartEmpty(true);
} else {
isErrorStartEmpty(false);
}
inputStart(e.target.value);
}}
onClick={(e) => {
if (e.target.value === "") {
isErrorStartEmpty(true);
}
}}
/>
{errorStartEmpty ? <span>Start date can't be empty</span> : <></>}
<label>End date</label>
<input
type="date"
name="email"
value={end}
onChange={(e) => {
inputEnd(e.target.value);
if (e.target.value === "") {
isErrorEndEmpty(true);
} else {
isErrorEndEmpty(false);
}
dateValidate();
}}
onClick={(e) => {
if (e.target.value === "") {
isErrorEndEmpty(true);
}
}}
/>
{errorEndEmpty ? <span>End date can't be empty</span> : <></>}
<input type="submit" value="Submit" />
</form>
<h2>{intern.name}</h2>
<h2>{intern.email}</h2>
<h2>{intern.internshipStart}</h2>
<h2>{intern.internshipEnd}</h2>
</div>
);
};
export default EditIntern;
It has two inputs of type date. The task is to check that the start date is not greater than the end date.
I created a dateValidate function for this (which doesn't work as it should).
How can you solve this problem? (Perhaps my approach to form validation is generally not correct, I’ll be happy to read about my mistakes)
transform start date and end date to milliseconds new Date(start date).getTime() than compare it (>, <, >=) to the end date also transformed into milliseconds
first select right property
// inputEnd(e.target.value);
if (!isNaN(e.target.valueAsNumber)) inputStart(e.target.valueAsNumber);
// ...
//...
// inputEnd(e.target.value);
if (!isNaN(e.target.valueAsNumber)) inputEnd(e.target.valueAsNumber);
then validate
// ..when user submits start validation
const onFormSubmit = (e) => {
e.preventDefault()
// ...
if (start < end) {
// blah blah....
}
}
or better add min and max value so you dont have to check all
<input type="date" name="start" min="2017-01-01" max="2022-01-01">
also please dont use onChage with onClick event listeners its very bad practice
use either one of them, in this case onChage is pretty good.
seems use are using onClick for validating, use useEffect for validating and keep separate state for errors (object).
and check more options here MDN docs and play around with devtools (right click on element, select use in console option and see what properties it holds)

React form how to get user data based on a toggle on/off

I have a form in React JS with one toggle/switch. If toggle/switch is on, then two inputs appear in the screen. So i want to get user data if the user types in inputs and the toggle/switch is on and stays on. So if the user types in inputs but he toggles/switches again to off then input values get reset and when he saves the form i must get empty user data(i get the initial values). How can i achieve something like this? I'm checking in submit handler if the switch button is false and im setting the usestate to the initial values, but it doesnt work.
My code:
Form.js
import React, { useRef, useState } from "react";
import Wrapper from "./UI/Wrapper";
import Switch from '#mui/material/Switch';
import "./Form.css";
const Form = () => {
const [showCertification, setShowCertification] = useState(false);
const [enteredCodecert, setEnteredCodecert] = useState('');
const codecertRef = useRef();
const [codesteps, setCodesteps] = useState([{ value: null }]);
const codestepsRef = useRef();
const enteredCodecertIsValid = showCertification && enteredCodecert.trim() !== '';
const codecertInputIsInvalid = !enteredCodecertIsValid;
const codestepsIsValid = showCertification && codesteps.length >= 1 && codesteps.every(codestep => codestep.value !== null && codestep.value.trim() !== '');
const codestepInputIsInvalid = !codestepsIsValid;
const showCertificationHandler = (event) => {
setShowCertification(prevState => !prevState);
if (!showCertification) {
setEnteredCodecert('');
setCodesteps([{value: null}]);
}
}
const codecertChangeHandler = (event) => {
setEnteredCodecert(event.target.value);
}
const stepChangeHandler = (i, event) => {
const values = [...codesteps];
values[i].value = event.target.value;
setCodesteps(values);
}
const addStepHandler = (event) => {
event.preventDefault();
const values = [...codesteps];
values.push({ value: null });
setCodesteps(values);
}
const removeStepHandler = (i, event) => {
event.preventDefault();
const values = [...codesteps];
values.splice(i, 1);
setCodesteps(values);
}
const submitHandler = (event) => {
event.preventDefault();
if (!enteredCodecertIsValid && showCertification) {
codecertRef.current.focus();
return;
}
if (!codestepsIsValid && showCertification) {
if (codesteps.length >= 1) {
codestepsRef.current.focus();
return;
}
return;
}
if (showCertification === false) {
setEnteredCodecert('');
setCodesteps([{value: null}]);
}
console.log(enteredCodecert);
console.log(codesteps);
}
return (
<Wrapper>
<form onSubmit={submitHandler}>
<fieldset className={`${(showCertification && codecertInputIsInvalid) || (showCertification && codestepInputIsInvalid) ? 'govgr-form-group__error' : '' }`}>
<legend><h3 className="govgr-heading-m">Certifications</h3></legend>
<Switch id="certification" checked={showCertification} onClick={showCertificationHandler} inputProps={{ 'aria-label': 'controlled' }} />
<label className="govgr-label govgr-!-font-weight-bold cert-label" htmlFor="certification">Certification</label>
{showCertification && (
<div>
<div className="govgr-form-group">
<label className="govgr-label govgr-!-font-weight-bold" htmlFor="codecert">Code Certification*</label>
{codecertInputIsInvalid && <p className="govgr-error-message"><span className="govgr-visually-hidden">Λάθος:</span>Code Certification is required.</p>}
<input className={`govgr-input govgr-!-width-three-quarter ${codecertInputIsInvalid ? 'govgr-error-input' : ''}`} id="codecert" name="codecert" type="text" value={enteredCodecert} ref={codecertRef} onChange={codecertChangeHandler} />
</div>
<div className="govgr-form-group">
<label className="govgr-label govgr-!-font-weight-bold" htmlFor="codestep">Code STEPS*</label>
{codestepInputIsInvalid && <p className="govgr-error-message"><span className="govgr-visually-hidden">Λάθος:</span>Code STEPS are required.</p>}
{codesteps.map((field, idx) => {
return (
<div key={`${field}-${idx}`}>
<div className="flex-row">
<input className={`govgr-input govgr-input--width-10 input-step ${codestepInputIsInvalid ? 'govgr-error-input' : ''}`} id="codestep" type="text" ref={codestepsRef} value={field.value || ""} onChange={e => stepChangeHandler(idx, e)} />
<button className="govgr-btn govgr-btn-warning remove-step" onClick={(e) => removeStepHandler(idx, e)}>Χ</button>
</div>
</div>
);
})}
<button className="govgr-btn govgr-btn-secondary button-step" onClick={addStepHandler}>Add Code Step</button>
</div>
</div>
)}
</fieldset>
<button className="govgr-btn govgr-btn-primary btn-center" type="submit">Save</button>
</form>
</Wrapper>
);
};
export default Form;
The issue is that in showCertificationHandler when you toggle the showCertification you are expecting the state update to be immediate.
const showCertificationHandler = (event) => {
setShowCertification(prevState => !prevState);
if (!showCertification) {
setEnteredCodecert('');
setCodesteps([{value: null}]);
}
}
This is not the case with React state updates, however. React state updates are enqueued and asynchronously processed.
To resolve, move the "reset" logic into an useEffect hook with a dependency on the showCertification state.
const showCertificationHandler = () => {
setShowCertification((prevState) => !prevState);
};
useEffect(() => {
if (!showCertification) {
setEnteredCodecert("");
setCodesteps([{ value: null }]);
}
}, [showCertification]);
For the same reason above, when resetting the states in your submitHandler they are enqueued and asynchronously processed, so console logging the state immediately after will only ever log the state values from the current render cycle, not what they will be on a subsequent render cycle. You can remove the "reset" logic from submitHandler.
const submitHandler = (event) => {
event.preventDefault();
if (!enteredCodecertIsValid && showCertification) {
codecertRef.current.focus();
return;
}
if (!codestepsIsValid && showCertification) {
if (codesteps.length >= 1) {
codestepsRef.current.focus();
return;
}
return;
}
console.log({enteredCodecert, codesteps});
};

Pulling a setState from child component and then using it as a value in parent component

I created a stopwatch and I am attempting to take the value of the stopwatch and pass it through a form component. Currently, when trying to push it through using 'props', it isn't connecting to the specific 'setTime' const determined in the StopWatch component.
I am using react-hook-form, and Styled Components throughout the project. And currently I don't have anything passed through my "value" in my controller because everything I'm trying to do just isn't working.
Here is the stop watch component:
import React, { useEffect, useState } from "react";
const StopWatch = (props) => {
const [time, setTime] = useState(0);
const [timerOn, setTimeOn] = useState(false);
useEffect(() => {
let interval = null;
if (timerOn) {
interval = setInterval(() => {
setTime((prevTime) => prevTime + 10);
}, 10);
} else {
clearInterval(interval);
}
return () => clearInterval(interval);
}, [timerOn]);
// const updateTimeLogged = (e) => {
// props.setTimeOn(e.target.value);
// };
return (
<div>
<div>
<span>{("0" + Math.floor((time / 60000) % 60)).slice(-2)}:</span>
<span>{("0" + Math.floor((time / 1000) % 60)).slice(-2)}:</span>
<span>{("0" + ((time / 10) % 100)).slice(-2)}</span>
</div>
<div>
{!timerOn && time === 0 && (
<button onClick={() => setTimeOn(true)}>Start</button>
)}
{timerOn && <button onClick={() => setTimeOn(false)}>Stop</button>}
{!timerOn && time !== 0 && (
<button onClick={() => setTimeOn(true)}>Resume</button>
)}
{!timerOn && time > 0 && (
<button onClick={() => setTime(0)}>Reset</button>
)}
</div>
</div>
);
};
export default StopWatch;
And here is my form component:
import {
Button,
Form,
Input,
GridContainer,
Label,
InputWrapper,
DateWrapper,
NotesWrapper,
StopWatchWrapper,
} from "./PracticeLog.styled";
import { useForm, Controller } from "react-hook-form";
import { useState } from "react";
import StopWatch from "./StopWatch";
const PracticeLogInput = (props) => {
const { register, handleSubmit, control } = useForm();
const [result, setResult] = useState("");
const onSubmit = (data) => console.log(data);
return (
<GridContainer>
<Form onSubmit={handleSubmit(onSubmit)}>
<DateWrapper>
<Label>Date</Label>
<Input type="date" {...register("Date")} placeholder="Date"></Input>
</DateWrapper>
<NotesWrapper>
<Label>Notes</Label>
<Input type="text" {...register("Notes")} placeholder="Notes"></Input>
</NotesWrapper>
<StopWatchWrapper>
<Controller
name="time"
control={control}
onChange={(e) => setInterval(e.target.value)}
value={} //<-- this is where I need to put the value I get from 'setTime' in '/.StopWatch'.
render={StopWatch}
/>
</StopWatchWrapper>
<Button type="Submit">Submit</Button>
</Form>
</GridContainer>
);
};
export default PracticeLogInput;
If you see anything I can improve on, please let me know.
Try using this code but your code is little bit complex try making it simpler bro
import {
Button,
Form,
Input,
GridContainer,
Label,
InputWrapper,
DateWrapper,
NotesWrapper,
StopWatchWrapper,
} from "./PracticeLog.styled";
import { useForm, Controller } from "react-hook-form";
import { useState } from "react";
import StopWatch from "./StopWatch";
const PracticeLogInput = (props) => {
const { register, handleSubmit, control } = useForm();
const [time, setTime] = useState(0)
const [result, setResult] = useState("");
const onSubmit = (data) => console.log(data);
return (
<GridContainer>
<Form onSubmit={handleSubmit(onSubmit)}>
<DateWrapper>
<Label>Date</Label>
<Input type="date" {...register("Date")} placeholder="Date"></Input>
</DateWrapper>
<NotesWrapper>
<Label>Notes</Label>
<Input type="text" {...register("Notes")} placeholder="Notes"></Input>
</NotesWrapper>
<StopWatchWrapper>
<Controller
name="time"
control={control}
onChange={(e) => setInterval(e.target.value)}
value={time} //<-- this is where I need to put the value I get from 'setTime' in '/.StopWatch'.
render={<StopWatch
time={time}
setTime={setTime}
/>}
/>
</StopWatchWrapper>
<Button type="Submit">Submit</Button>
</Form>
</GridContainer>
);
};
export default PracticeLogInput;
And in StopWatch component change the code like this
const StopWatch = (props) => {
const {time,setTime}=props
const [timerOn, setTimeOn] = useState(false
);
//rest
Note : The flow is like parent to child you can't pull a state from child to parent directly instead define the state in parent and pass it as props to child. And change the state from child using the props itself.

How can I access key using value in ReactJs?

I'm following a reactJS tutorial from Udemy and I was trying something on my own.
Project:
This is a simple project where I can add or remove goals
What I want to add extra is I want to clear the input text field when clicked on submit(Add goal) button. And I am able to do it but I think there is one problem.
The Whole Code
import React, { useState } from "react";
import Button from "../../UI/Button/Button";
import style from "./CourseInput.module.css";
const CourseInput = (props) => {
const [enteredValue, setEnteredValue] = useState("");
const [isValid, setIsValid] = useState(true);
const goalInputChangeHandler = (event) => {
setEnteredValue(event.target.value);
if (enteredValue.trim().length > 0) {
setIsValid(true);
}
console.log("=>" + enteredValue);
};
const formSubmitHandler = (event) => {
event.preventDefault();
if (enteredValue.trim().length === 0) {
setIsValid(false);
return;
}
props.onAddGoal(enteredValue);
// empty the inputbar and reset state (enteredValue)
console.log(event);
event.target[0].value = ""; // the main
setEnteredValue(""); // two lines.
};
return (
<form onSubmit={formSubmitHandler}>
<div className={`${style["form-control"]} ${!isValid && style.invalid}`}>
<label>Course Goal</label>
<input type="text" onChange={goalInputChangeHandler} />
</div>
<Button type="submit">Add Goal</Button>
</form>
);
};
export default CourseInput;
as you can see in above code I'm accessing input field through form events.
I accessed the input field through index number which I think is hard coded. In future if number of form element increases/decreases there is a chance that index number might change. so what I want to do is access the input value without using index. Is that possible?(I know it is), and how do I do it?
If you are working with a form's onSubmit action and have the onSubmit event then you can reset the form directly.
const formSubmitHandler = (event) => {
event.preventDefault();
if (enteredValue.trim().length === 0) {
setIsValid(false);
return;
}
props.onAddGoal(enteredValue);
setEnteredValue("");
event.target.reset(); // <-- calls form's reset action
};
const CourseInput = (props) => {
const [enteredValue, setEnteredValue] = React.useState("");
const [isValid, setIsValid] = React.useState(true);
const goalInputChangeHandler = (event) => {
setEnteredValue(event.target.value);
if (enteredValue.trim().length > 0) {
setIsValid(true);
}
};
const formSubmitHandler = (event) => {
event.preventDefault();
if (!enteredValue.trim().length) {
setIsValid(false);
return;
}
props.onAddGoal(enteredValue);
setEnteredValue("");
event.target.reset();
};
return (
<form onSubmit={formSubmitHandler}>
<div>
<label>Course Goal</label>
<input type="text" onChange={goalInputChangeHandler} />
</div>
<button type="submit">Add Goal</button>
</form>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(
<CourseInput onAddGoal={(val) => console.log(val)} />,
rootElement
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="root" />
You may use Refs in order to achieve this:
function MyComponent() {
const textInput = React.useRef(null);
const formSubmitHandler = (event) => {
event.preventDefault();
if (enteredValue.trim().length === 0) {
setIsValid(false);
return;
}
props.onAddGoal(enteredValue);
// empty the inputbar and reset state (enteredValue)
console.log(event);
textInput.current.value = "";
};
// other code
return <input type="text" onChange= {goalInputChangeHandler} ref={textInput} />
}
It's enough to add value={enteredValue} to input field and set it to empty string after submit the form.
Also if you have any other input field, you can try event.target.reset().
So try this:
import React, { useState } from "react";
// import styled from "styled-components";
import Button from "../../UI/Button/Button";
import style from "./CourseInput.module.css";
const CourseInput = (props) => {
const [enteredValue, setEnteredValue] = useState("");
const [isValid, setIsValid] = useState(true);
const goalInputChangeHandler = (event) => {
setEnteredValue(event.target.value);
if (enteredValue.trim().length > 0) {
setIsValid(true);
}
console.log("=>" + enteredValue);
};
const formSubmitHandler = (event) => {
event.preventDefault();
if (enteredValue.trim().length === 0) {
setIsValid(false);
return;
}
props.onAddGoal(enteredValue);
// empty the inputbar and reset state (enteredValue)
setEnteredValue("");
event.target.reset();
};
return (
<form onSubmit={formSubmitHandler}>
<div className={`${style["form-control"]} ${!isValid && style.invalid}`}>
<label>Course Goal</label>
<input type="text" value={enteredValue} onChange={goalInputChangeHandler} />
</div>
<Button type="submit">Add Goal</Button>
</form>
);
};
export default CourseInput;

How to have changeable values in input React JS?

I was trying to set my value in the input value! but after that, I cannot write anything in the input field! I wanted to set values from the back end in value!
We are writing an admin channel to edit the article for that we need already existing article values to edit the article! What am I doing wrong! or Maybe you can suggest a better way to edit the article in the admin channel!
here is the code:
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { useParams } from 'react-router';
const EditArticle = (props) => {
const [editValues, setEditValues] = useState([]);
const [changedValues, setChangedValues] = useState('');
console.log('values', editValues);
console.log('changed', changedValues);
const params = useParams();
console.log(params);
const resultsId = params.id;
console.log('string', resultsId);
const [authTokens, setAuthTokens] = useState(
localStorage.getItem('token') || ''
);
const setTokens = (data) => {
localStorage.setItem('token', JSON.stringify(data));
setAuthTokens(data);
// setToken(data['dataValues']['token']);
};
useEffect(() => {
const fetchData = async () => {
try {
const res = await axios.get(
`${process.env.REACT_APP_API_URL}/article/${resultsId}`
);
setEditValues(res.data);
} catch (err) {}
};
fetchData();
}, [resultsId]);
const inputValue = editValues;
const userToken = props.token;
return (
<div>
<form value={{ authTokens, setAuthTokens: setTokens }}>
<input
value={editValues.title || ''}
onChange={(input) => setChangedValues(input.target.value)}
type='text'
/>
<input
// ref={editValues.shortDesc}
value={editValues.shortDesc}
onChange={(input) => setChangedValues(input.target.value)}
type='text'
/>
<button type='submit'>send</button>
</form>
</div>
);
};
export default EditArticle;
your onChange handler is updating a different state property than what is being used as the value on the input (editValues vs changedValues).
Also you can pass a defaultValue to input that will get used as the default value only.
See more here https://reactjs.org/docs/uncontrolled-components.html
you can use just do it just using editValues. try this:
I just reproduced it without the api call to run the code.
import React, { useState, useEffect } from "react";
const EditArticle = (props) => {
const [editValues, setEditValues] = useState([]);
console.log("values", editValues);
const [authTokens, setAuthTokens] = useState(
localStorage.getItem("token") || ""
);
const setTokens = (data) => {
localStorage.setItem("token", JSON.stringify(data));
setAuthTokens(data);
// setToken(data['dataValues']['token']);
};
useEffect(() => {
const fetchData = async () => {
try {
//here get the data from api and setstate
setEditValues({ title: "title", shortDesc: "shortDesc" });
} catch (err) {}
};
fetchData();
}, []);
return (
<div>
<form value={{ authTokens, setAuthTokens: setTokens }}>
<input
value={editValues.title || ""}
onChange={(input) => setEditValues({title: input.target.value})}
type="text"
/>
<input
value={editValues.shortDesc}
onChange={(input) => setEditValues({shortDesc: input.target.value})}
type="text"
/>
<button type="submit">send</button>
</form>
</div>
);
};
export default EditArticle;

Categories