For some reason(THIS reason I still can not say clearly, can you help me to describe a complete 🤕)We can’t get the latest state from methods called in React at certain times, such as event listening

For example, add a DOM to a page that listens for a click and outputs the value of count, which may be changed by other methods

If we write class, we don’t have this problem, because in the execution method we take the value directly from this.state, which is always up to date; You can also use the setState callback if you immediately need to do something else with the latest value

state = { count: 0, }; Document.addeventlistene ("click", () => handleClick(), True)} componentWillUnmount () {/ / document to remove event listeners. RemoveEventListener (" click ", () = > handleClick (), true) } const handleClick = () => { this.setState({ count: This.state.count + 1 // set a new value}, () => {// state is the latest console.log(this.state.count)})}Copy the code

When using React Hooks, the normal way to write it is

const [count, setCount] = useState<number>(0); UseEffect (() => {document.addeventListene ("click", handleClick, True) return () = > {/ document/removing event listeners. The removeEventListener (" click ", handleClick, true)}}, []) const handleClick = () => {console.log(count); setCount(count+1); }Copy the code

Count always outputs the initial value of 0, and then the page render value of count will never change except after the first click from 0 to 1

Solutions:

  1. As the value of state changes, we can useEffect to listen for this change in state. When state changes, the last listen is cancelled and a new listen is restarted, so that the state obtained in the listener execution method is always the latest
UseEffect (() => {document.addeventListene ("click", handleClick, True) return () = > {/ document/removing event listeners. The removeEventListener (" click ", handleClick, true)}}, [count])Copy the code

This is one solution, but each change in count cancels the previous listener and rebinds the listener, which can consume memory if there are more of these operations

  1. Hold mutable variables by ref, declare a useRef, assign the new value to the ref every time state is updated, and use the ref instead of state in the execution method
const [count, setCount] = useState<number>(0); const countRef = useRef<number>(count); UseEffect (() => {document.addeventListene ("click", handleClick, True) return () = > {/ document/removing event listeners. The removeEventListener (" click ", handleClick, true)}}, []) useEffect(() => { countRef.current = count; // make countref.current always the same as count, }, [count]) const handleClick = () => {// use countref.current instead of count console.log(count); setCount(countRef.current+1); }Copy the code

After running, you will find that the count printed in the listener function is still the original value of 0, but the page rendering count is always changing

We need to know that the count we get in the handleClick function is no longer the same thing as the count we get outside the handleClick function. The count inside the function is already determined when we start listening for document.addeventListene.

These are the two methods I know of so far, update when there is a better one