React Typescript input onChange event type? - reactjs

I'm trying to get text from a input element, setting it to state and then rendering it back into the input box. However I think my event typing is wrong? I've searched online and tried implementing many solutions but none have worked so far. Any help is appreciated.
my component:
import React, { ChangeEvent, ChangeEventHandler, useState } from "react";
export default function Unidirectionflow() {
const [state4, setState4] = useState("");
const [state5, setState5] = useState("");
let handleChange4 = (e: React.FormEvent<HTMLInputElement>): void => {
setState3((e.target as HTMLInputElement).value);
};
let handleChange5 = (event: ChangeEvent<HTMLInputElement>) => {
setState5(event.currentTarget.value);
};
return (
<main>
<input type="text" value={state4} onChange={() => handleChange4} />
<input type="text" value={state5} onChange={() => handleChange5} />
</main>
);
}
Typescript input onchange event.target.value
React TypeScript: Correct Types for onChange
Can't type in React TextField Input
https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/forms_and_events/

You can do like this
export default function Unidirectionflow() {
const [states, setStates] = useState({
state3:'',
state4:''
})
const handleChange = (
e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>
) => {
setStates({
...states,
[e.target.name]: e.target.value.trim(),
});
};
return (
<main>
<input type="text" name="state3" value={states.state3} onChange={handleChange} />
<input type="text" name="state4" value={states.state4} onChange={handleChange} />
</main>
);
};

onChange={handleChange}
See if this can help you!

Just do this:
handleChange = (event: Event) => {
const { value } = event.target as unknown as { value: string };
setState(value);
};
<input type='text' onChange={handleChange} />
And the squeegee lines will go away.

You have forgot to pass the event when calling the function
Try this
onChange={(e) => handleChange(e)}
Or
onChange={handleChange}
Code sandbox => https://codesandbox.io/s/dreamy-pateu-1mc6j?file=/src/App.tsx

Related

Email Validation in React Functional Component

Using React functional component, I'm trying to validate the email address. Below is my code.
Problem is when I tried to enter any text nothing happens, its not allowing any letters to be entered.
Below is my component code, Please help me out
const UpdateEmailAddress: React.FC<Step> = (props: Step) => {
const [customerEmail, setCustomerEmail] = useState<any>('');
const [checkValidEmail, setcheckValidEmail] = useState<boolean | null>(null);
const emailValidate = (value: any) => {
if (!validEmailRegex(value)) {
setcheckValidEmail(true);
} else {
setcheckValidEmail(false);
}
};
const handleChange = (e: any) => {
if (e.target.value) {
setCustomerEmail(e.target.value);
}
};
return (
<>
<div className="step container update-email-container pt-10" ref={props.domRef}>
<div className="row">
<div className="col-md-4">
<div className="mb-4">
<TextField
aria-label={content.emailAddress.header}
enableClearText
errormessage={content.emailAddress.emailError}
helptext={content.emailAddress.helptext}
id="emailAddress"
isValid={checkValidEmail}
label={content.emailAddress.emailAddress}
maxLength={0}
name="emailAddress"
tooltipText=""
type="email"
onChange={(e:any) => handleChange(e)}
value={customerEmail}
/>
</div>
<ButtonAction
onClick={emailValidate(customerEmail)}
className="load-more-button mb-0"
type="button"
aria-label={content.emailAddress.nextButton}
>
{content.emailAddress.nextButton}
</ButtonAction>
</div>
</div>
</div>
</>
);
};
Your logic in onChange method is wrong it should be
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setCustomerEmail(e.target.value)}
You have to define the onChange() method.
It should be like this
const handleChange = (e) => {
setCustomerEmail(e.target.value);
};
Then you will be able to enter textfield.
Secondly, you have to pass the value in emailvalidate() in onClick() of button.
<ButtonAction onClick={()=>emailValidate(customerEmail)} className="load-more-button mb-0" type="button" aria-label={content.emailAddress.nextButton}>
{content.emailAddress.nextButton}
</ButtonAction>
And remove e parameter in emailValidate(value) as it is only using value and not e.

How to do validation using useRef()

How do I validate input box value using useRef .
Initial validation is not required once user clicks on input box and comes out then it should validate if input box is empty it should show input box cannot be empty.
Codesandbox Link
code i tried. using onBlur
export default function App() {
const name = React.useRef("");
const nameBlurData = (name) => {
console.log("name", name);
};
return (
<div className="App">
<form>
<input
onBlur={() => nameBlurData(name.current.value)}
type="text"
ref={name}
placeholder="Enter First Name"
/>
// show error message here
</form>
</div>
);
}
You can use "useRef" to validate the value of an input field.
No need to use "useState".
Below code is a basic implementation of OP's question
You can replace the "console.log" with your alert component.
import { useRef } from "react";
const ComponentA = () => {
const emailRef = useRef(null);
const passwordRef = useRef(null);
const onBlurHandler = (refInput) => {
if (refInput.current?.value === "") {
console.log(`${refInput.current.name} is empty!`);
}
}
return (
<form>
<input ref={emailRef} onBlur={onBlurHandler.bind(this, emailRef)} />
<input ref={passwordRef} onBlur={onBlurHandler.bind(this, passwordRef)} />
<form/>
)
}
Link to "useRef"
Note: Not tested, code typed directly to SO's RTE
You can use a local state and conditionally render an error message like this:
const [isValid, setIsValid] = useState(true)
const nameBlurData = (name) => {
setIsValid(!!name);
};
return (
<div className="App">
<form>
<input
onBlur={() => nameBlurData(name.current.value)}
type="text"
ref={name}
placeholder="Enter First Name"
/>
{!isValid && <span> input must not be empty </span> }
</form>
Note that you don't really need a ref in this case, you can just use the event object like:
onBlur={(event) => nameBlurData(event.target.value)}
You need to use useState hook to update the value of the name property. Using ref is not ideal here.
Live demo https://stackblitz.com/edit/react-apqj86?devtoolsheight=33&file=src/App.js
import React, { useState } from 'react';
export default function App() {
const [name, setName] = useState('');
const [hasError, setError] = useState(false);
const nameBlurData = () => {
if (name.trim() === '') {
setError(true);
return;
}
setError(false);
};
return (
<div className="App">
<form>
<input
onBlur={nameBlurData}
type="text"
value={name}
onChange={e => setName(e.target.value)}
placeholder="Enter First Name"
/>
{hasError ? <p style={{ color: 'red' }}>Name is required</p> : null}
</form>
</div>
);
}

Passing React Hook to functional component

I'm looking to create a functional component that takes in a hook and its Set function as parameters and constructs an associated input using those fields (along with some other fields). Running into issues with passing in spread operators (as advised in "Learning React, 2nd edition"). Relevant snippets below, help appreciated!
Generic function that takes in an initial value and returns a new hook and its setValue function:
export const useInput = (initialValue) => {
const [value, setValue] = useState(initialValue);
return [
{ value, onChange: (e) => setValue(e.target.value) },
() => setValue(initialValue),
];
};
The hook to be used:
const [firstName, setFirstName] = useInput("");
The functional component (after some cleanup)
const MyInputComp = (props) => {
return (
<div>
<input
className="blah-blah-blah"
{props.obj} // *ERROR*
type="text"
placeholder={props.placeholder}
required={props.required}
/>
</div>
);
};
Here's how the component is invoked:
<MyInputComp
text="First Name"
obj={...firstName} // *ERROR*
placeholder="Jon"
required={true}
/>
Issue
You are not consuming the input value and updater correctly.
The are returned as { value, onChange: (e) => setValue(e.target.value) }
but you are passing singly as obj
obj={...firstName}
and
const MyInputComp = (props) => {
return (
<div>
<input
className="blah-blah-blah"
{props.obj} // *ERROR*
type="text"
placeholder={props.placeholder}
required={props.required}
/>
</div>
);
};
Solution
Spread the value and onChange props into the underlying input
const MyInputComp = (props) => {
return (
<div>
<input
className="blah-blah-blah"
{...props.obj} // <-- spreads value & onChange props
type="text"
placeholder={props.placeholder}
required={props.required}
/>
</div>
);
};
Since MyInputComp appears to be simply proxying some props you can spread them all in and then destructure what you need.
const MyInputComp = (props) => {
return (
<div>
<input
className="blah-blah-blah"
{...props} // <-- spread all passed props
type="text"
/>
</div>
);
};
Use
const [firstName, setFirstName] = useInput("");
<MyInputComp
text="First Name"
{...firstName} // <-- spread to input
placeholder="Jon" // <-- spread to input
required={true} // <-- spread to input
/>
You will need to do couple of changes. First spread the props.obj object so that input element under the hood can take value and onChange props. Such as
const MyInputComp = (props) => {
return (
<div>
<input
className="blah-blah-blah"
{...props.obj}
type="text"
placeholder={props.placeholder}
required={props.required}
/>
</div>
);
};
Then render the MyInputComp like that
<MyInputComp
text="First Name"
obj={firstName}
placeholder="Jon"
required={true}
onChange={handleNameChange}
/>
Also in the custom useInput hook the change function should be like
(value) => setValue(value)
instead of () => setValue(initialValue)

Why does react turn my state into [object object]

I've got this straightforward component:
Here it is on CodeSandbox: https://codesandbox.io/s/fast-architecture-fgvwg?fontsize=14&hidenavigation=1&theme=dark
function Home() {
const [name, setName] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
console.log(name);
};
return (
<>
<form onSubmit={handleSubmit}>
<input
value={name}
onChange={setName}
type="text"
placeholder="name"
/>
<button type="submit">
submit
</button>
</form>
</>
);
}
export default Home;
As soon as I click in the input box, it turns into [object object] and I'd love to know why this is happening.
You are not passing a value to your name variable onChange. onChange returns event which you have to get the value from and set the name that way.
import React, { useState } from "react";
import "./styles.css";
export default function App() {
const [name, setName] = useState("");
const handleSubmit = e => {
e.preventDefault();
console.log(name);
};
return (
<>
<form onSubmit={handleSubmit}>
<input value={name} onChange={(e) => setName(e.currentTarget.value)} type="text" placeholder="name" />
<button type="submit">submit</button>
</form>
</>
);
}
The update here is the onChange attribute. You are grabbing the event e and setting the name to whatever that currentTarget value is.
onChange = { (e) => setName(e.currentTarget.value) }
Your onChange handler receives a change event object. If you want the new value you'll need to get it from the event: event.target.value:
<input
value={name}
onChange={e => setName(e.target.value)}
type="text"
placeholder="name"
/>
When you cast a value to a string, like when calling console.log, the value's toString method is invoked, which for objects returns [object Object] by default.
You had onChange set to setName. Setname is a function used to update the value of name.
You need to write a function to handle the name value being updating when the user types in a name. Set onChange equal to that function:
import React, { useState } from "react";
import "./styles.css";
export default function App() {
const [name, setName] = useState("");
const handleSubmit = e => {
e.preventDefault();
console.log(name);
};
function handleChange(e) {
e.preventDefault();
setName(e.target.value);
}
return (
<>
<form onSubmit={handleSubmit}>
<input
value={name}
onChange={handleChange}
type="text"
placeholder="name"
/>
<button type="submit">submit</button>
</form>
</>
);
}

React TypeScript: Alternatives to UseRef in functional components

Is there another way of getting/setting the values from the dom that is less expensive than useRef()? Is useRef() to be used lightly as the docs suggest?
import React, { useRef, useEffect } from 'react';
const Join: React.FC = () => {
const fullName = useRef<HTMLInputElement>(null);
const email = useRef<HTMLInputElement>(null);
const password = useRef<HTMLInputElement>(null);
const myForm = useRef<HTMLFormElement>(null);
useEffect(() => {
if (myForm.current) myForm.current.reset();
if (fullName.current) fullName.current.focus();
}, []);
return (
<div>
<form ref={myForm}>
<input type='text' ref={fullName} />
<input type='text' ref={email} />
<input type='text' ref={password} />
</form>
</div>
)
}
When the component loads I want to clear the form and focus the
fullName input
You don't need refs for that
I want to clear the form
Make your inputs controlled
Declare an empty string as initial value
const Component = () =>{
const [state, setState] = useState({
email : '',
password : ''
})
const onChange = ({ target: { value, name } }) =>{
setState(prev => ({
...prev,
[name] : value
}))
}
const { email, password } = state
return(
<>
<input value={email} onChange={onChange} id='email'/>
<input value={password} onChange={onChange} id='password' />
</>
)
}
Automatically focus a given input
Just use autofocus for that
<input autofocus/>

Resources