Reputation: 4035
I've tried almost every solution similar to my problem, yet none is working. I have a simple state and changing the value of this state in a function as like below, handleOnClick
is calling in a button's onClick
event. I'm also using Router(if it's change something);
import { useState} from "react"
import { BrowserRouter as Router, Route, Link, useHistory} from "react-router-dom";
const Buton = () => {
let x = "";
const [lowerState, setLower] = useState("")
const history = useHistory();
const handleOnClick = () => {
x = document.getElementById("my_input").value.toLowerCase();
setLower(x)
console.log(x) //this prints the current value
console.log(lowerState) //this DOES NOT prints the current value, but
// when I put another text into the input and click
// to button, it prints the first value I put here
history.push('/test', {params : lowerState})
};
.
.
.
return (...)
}
export default Buton
Now x
is a value that returns from an input
HTML element. When I set this value as a state and console log, it doesn't print the value first, when I put something in input again, then it prints the first value. So it's like it's coming 1 step behind.
I've used useEffect()
, I did put a second parameter to setLower
as console.log(lowerState)
and other things on the internet that people suggested, but none is working. Every time, the state is coming 1 step behind. How can I make this state changes immediately?
Upvotes: 1
Views: 1574
Reputation: 388
If you want to use the value of an input in a user event function, the best way (and least buggy) is to bind your input value to local state and then just reference that state in your callback function.
Please try to avoid imperatively pulling values from the DOM using getElementById
etc. Here's what I mean:
const [value, setValue] = useState('');
// This will keep everything updated until you need to use it
handleChange(event) {
setValue(event.target.value);
}
// Then just grab whatever is in local state
handleClick() {
history.push('/test', {params : value});
}
return (
<input value={value} onChange={handleChange} />
// Your button is here too
)
Upvotes: 2
Reputation: 9
So i would like to suggest that use useRef if need for reference only object which may not causing rerendering. also using let x= "" is not correct, you should write code immutable way
const Buton = () => {
const lowerCaseRef = useRef("")
const history = useHistory();
const handleOnClick = () => {
lowerCaseRef.current =
document.querySelector("#my_input").value.toLowerCase();
console.log(lowerCaseRef.current) //this DOES NOT prints the current value, but
// when I put another text into the input and click
// to button, it prints the first value I put here
history.push('/test', {params : lowerCaseRef.current})
};
return (...)
}
Upvotes: 0
Reputation: 8412
Which mean that the state only gets an update after an eventHandler/function is finished
If you want to do some condition, wrap your logic inside a useEffect
useEffect(() => {
if (lowerState === "your-condition-value") {
history.push("/test", { params: lowerState });
}
}, [lowerState]);
Or in your case, just use the variable directly:
const handleOnClick = () => {
x = document.getElementById("my_input").value.toLowerCase();
history.push("/test", { params: x });
};
You should not worry about that since your app still working as expected
Upvotes: 0
Reputation: 388
When you call setLower(x)
, it doesn't immediately update the lowerState
. The new value will be available the next time it renders. Because of that the console.log(x)
"works" (since it uses the new value that you gain as a parameter) but console.log(lowerState)
uses the old value that hasn't updated to the state yet at that point.
If you want history.push('/test', {params : lowerState})
to work, then you need to use the x
there instead of lowerState
. Or call it within a useEffect
with the lowerState
and having lowerState
as a dependency parameter to the hook.
Upvotes: 1
Reputation: 4723
This is because when you call setLower(x)
it is not an async call. So it doesn't wait. That's why you get the 1 step before value in your state right after setting the value.
Official doc - https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous
Upvotes: 1