Why after onClick my hook is failing to update the state? - javascript

I have defined a constant to use UseState Hook in ReactJS by:
const [inputValue, setInputValue] = useState("")
Using the inputValue for my form in a way:
<form
data-testid="form"
onSubmit={e => {
e.preventDefault();
setLogFilters({
queryText: inputValue
});
}}
>
I am able to input string in my form using the snippet below:
<Input
name="input1"
type="text"
onChange={e => setInputValue(e.target.value)}
/>
I now have a button which onclick should clear the string input in the form:
<Button
onClick={() => {
setInputValue("");
}}
>
But the form retains the original string and the state is not set to null string. What is wrong? why is the hook not able to update the state?

As mention by #Corentin when you have any input field and you want its value to get change when you write something, you need to have a state for that, just like you have a state with name inputValue
you need to bind this state with your input through value prop i.e
<Input
//This will change your input when your state will be updated
value = {inputValue}
name="input1"
type="text"
onChange={e => setInputValue(e.target.value)}
/>
Now, the value will get change when you will set your inputValue state.

your input field does not have the value attribute, it should be like below:
<Input
name="input1"
type="text"
value={inputValue}
onChange={e => setInputValue(e.target.value)}
/>

For change the value of an input with hooks, you've to initialize your state like "value" in your input.
Example :
function onClick () {
setYourState('Blabla')
}
<input placeholder='Enter blabla' value={yourState} onChange={(e) => setYourState(e.target.value)}></input>

Related

what does it mean by form state living inside the DOM?

while learning the concept controlled components in Reactjs I came across this statement
controlled component: "A component which renders a form, but the source of truth for that form state lives inside of the component state rather than inside of the DOM"
what is a form state? and what does it mean by form state living inside of DOM or component?
could you please elaborate on it?
what is a form state?
The form state just means "the current values entered into the individual input elements of a form". They can be accessed through the individual input elements value property or through the <form> elements form data itself.
what does it mean by form state living inside of DOM or component
It just means that if you do not explicitly store those values in react state and pass them to the <input> during render it will just be kept in the HTML input elements itself. If you inspect an <input> element in the developer console you will see, that it has a value prop. Uncontrolled just means that you do not explicitly pass that value to the <input> and that you do not handle changes to the value yourself. If you need to access that value in your code you would have to get a ref to the <input> and read that value.
function UncontrolledForm() {
const handleSubmit = event => {
event.preventDefault();
// values are stored in the form but they can be accessed through the DOM node
const formData = new FormData(event.target);
console.log(Object.fromEntries(formData.entries()));
};
return (
<form onSubmit={handleSubmit}>
<label>
foo
<input name="foo" />
</label>
<label>
bar
<input name="bar" />
</label>
<button>submit</button>
</form>
);
}
Controlled on the other hand means that you "control" the value yourself by passing it to the <input> during render all the time.
function ControlledForm() {
// values are kept in react state
const [values, setValues] = useState({foo: '', bar: ''});
const handleChange = event =>
setValues(state => ({
...state,
[event.target.name]: event.target.value
}));
const handleSubmit = event => {
event.preventDefault();
console.log(values);
};
return (
<form onSubmit={handleSubmit}>
<label>
foo
{/* we explicitly pass a value and onChange handler and manage the values ourself */}
<input name="foo" value={values.foo} onChange={handleChange} />
</label>
<label>
bar
<input name="bar" value={values.bar} onChange={handleChange} />
</label>
<button>submit</button>
</form>
);
}

Change input value with useRef

I captured an element with the useRef hook of React.
if I use console.log(this.inputRef) I get:
<input aria-invalid="false" autocomplete="off" class="MuiInputBase-input-409 MuiInput-input-394" placeholder="Type ItemCode or scan barcode" type="text" value="2">
Is there a way to change the value of that element using this.inputRef? and then force its re-render?
It sounds like what you are looking for is the ImperativeHandle hook.
From React docs:
useImperativeHandle customizes the instance value that is exposed to parent components when using ref
The below code should work for you:
function ValueInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
changeValue: (newValue) => {
inputRef.current.value = newValue;
}
}));
return <input ref={inputRef} aria-invalid="false" autocomplete="off" class="MuiInputBase-input-409 MuiInput-input-394" placeholder="Type ItemCode or scan barcode" type="text" value="2">
}
ValueInput = forwardRef(ValueInput);
Documentation: https://reactjs.org/docs/hooks-reference.html#useimperativehandle
well, you could do:
<input ref={myRef} value={myRef.current.value} />
The only problem with that is that refs DO NOT update or reredender the component, so, the value would never update... rather than that it could throw you an error where you are attempting to make an uncontrolled input as controlled
may be this can help
return(
<input type="text" ref={inptRef} />
<button onClick={()=>inptRef.current.value = ""}>clear input</button>
)

React - Should I have a different input change event for each form input

I'm building a mortgage calculator app and I want to have it update in real-time in front of the user. To do this I need to update state whenever input is changed so that the component rerenders.
I plan to do this using the onChange event on each input field, my question is should the onChange event call a different function for each input to update that state property, or is there a way to have one function, and change the state property that is being updated.
For example here is my class Component with the form, state, and onInputChange function
class Calculator extends Component {
state = {
price: 250000,
term: 20
};
onInputChange = (event) => {
this.setState({ price: event.target.value })
};
render() {
return (
<div>
<form>
<label htmlFor="propertyPrice">Property Price</label>
<input
type="number"
id="propertyPrice"
name="propertyPrice"
value={this.state.price}
onChange={this.onInputChange}
/>
<label htmlFor="term">Mortgage Term</label>
<input
type="term"
id="term"
name="term"
value="3"
/>
</form>
</div>
);
}
}
As you can see on the Property Price input I'm using the onChange event to call the function onInputChange, which directly updates the price in the state. Do I need a new function for the mortgage term input, or can I use the one function and just change which state property I'm updating, if so, how can I determine which state property is being updated in the function?
I do it this way:-
Create a single onInputChange() like this
onInputChange = (name, value) = {
this.setState({[name]: value})
}
Now create any number of inputs but make sure your onChange handler receives a function like this
onChange = {(e) => onInputChange(nameOfInput, e.target.value)}
Make your form input tags name same as state name and then you can add this for every input's onChange handler.
const handleChange = (e) => {
this.setState({[e.target.name]: e.target.value});
}

How to get a input value onChange in react variable?

I have a search text box I need to get the value onchange send the request to API when I use the normal event.target method it shows error. how to rectify it as in onchange I need to call a function with some arguments so I cannot go by ease.
my text box is :
<input className="ReactSearchBox" name="search" placeholder="Search Doctors"
onClick={() => {
this.onProviderListing(this.state.skip,0);
this.onEnable();
}}
onChange={() =>this.onSearchProvider(this.state.skip,0)} />
my function where i need the onchange value is:
onSearchProvider(nSkip,nLimit,e){
this.setState({
limit:nLimit,
skip:nSkip,
listing: this.state.listing,
searching: !this.state.searching
})
//console.log(nlimit);
var headers = {
"Content-Type":"application/json",
"AccessToken":localStorage.TOKEN,
}
var _calObj = {initiatorId:localStorage.userid,visitType: "office", skip:nSkip,limit:"5", includeOfflineProviders:"true",searchQuery:"lo"}
I need to give my input values in search query onchange correspondingly, sort it out plz.
You're not passing event from input. Change the onChange prop to:
<input className="ReactSearchBox" name="search"
placeholder="Search Doctors"
onClick={() => {
this.onProviderListing(this.state.skip,0);
this.onEnable();
}}
onChange={(e) =>this.onSearchProvider(this.state.skip,0, e)}
/>
onSearchProvider(nSkip,nLimit,e){
const value = e.target.value; // text box value
}
You can update the onChange in jsx by passing the e event object also like:
onChange={(e) => this.onSearchProvider(this.state.skip,0,e)}
and in onSearchProvider you can access it like:
onSearchProvider(nSkip, nLimit, {target}){
// you can see search box text here on change
console.log(target.value)
}
You don't need to pass state values on onChange method call.
State will be consistent throughout component.
<input className="ReactSearchBox" name="search" placeholder="Search Doctors"
onChange={() =>this.onSearchProvider(0)}
/>
And you can get value from event of that input as event.target.value
onSearchProvider(nLimit,e){
// access your state values directly here like this.state.skip
const searching = e.target.value;
}

Can value of input box be set to to empty string on clicking submit button when the input is in a stateless functional component?

How to clear the value inside the input in function Admin after I click the "Add" button? Should i use another class based component instead of a functional component?
I have set the value of one of the input box as : value={props.item} and in the this.setState I update the value of item as item:"".
AddInfo(info){
let s = this.state.products;
let obj ={name:""};
obj.name=info.productName;
s.push(obj);
this.setState({
products:s,
item:"" //Here i set the value of item equal to an empty string.
})
console.log(this.state.products);
}
function Admin(props){
let productName="";
return (
<div>
<input type="text" required placeholder="Product Name" onChange={(e)=>{productName=e.target.value}} value={props.item}></input><br/>
<button type="Submit" onClick{(e)=>props.AddInfo({productName})}>Add</button>
</div>
)
}
You have to save your input within a local state of the input function:
AddInfo(info){
let s = this.state.products;
let obj ={name:""};
obj.name=info.productName;
s.push(obj);
this.setState({
products:s,
})
console.log(this.state.products);
}
function Admin(props){
const [productName, setProductName] = useState('');
return (
<div>
<input type="text" required placeholder="Product Name" onChange={(e)=> setProductName(e.target.value) value={productName}></input><br/>
<button type="Submit" onClick{(e)=> {props.AddInfo({productName}); setProductName('')}}>Add</button>
</div>
)
}
This will work for you, since you are not mutating the productName variable anymore but now you are saving it in a local state of that input function.
Hope this helps!
Admin is like a form, and the main decision you have to make is rather you want it to be controlled (info is stored in stated, and state is reflected in the ui), or uncontrolled (info is taken from the dom once 'Add' is clicked.
Since you want to empty the input once 'Add' is clicked it makes sense to make this component controlled.
The next decision is rather you want it to be a functional component, or a class component. In nowadays it doesn't really matter (functional components can now use state with the state hook).
To store state in you functional component use React's useState hook.
function Admin({addInfo}){
const [productName, setProductName] = useState(")
return (
<div>
<input
type="text"
placeholder="Product Name"
onChange={(e)=>{
setProductName(e.target.value)
}
value={prodcutName}>
</input>
<button
onClick{(e)=>{
props.addInfo({productName})
setProductName("") // Will set the input to an empty string
}
>
Add
</button>
</div>
)
}

Categories