react (including hooks) synchronously get state value
environment
"dependencies": { "babel-plugin-transform-decorators-legacy": "^1.3.5", "customize-cra": "^1.0.0", "rc-form": "^2.4.11", "react": "^17.0.1", "react-app-rewired": "^2.1.8", "react-dom": "^17.0.1", "react-router-dom": "^5.2.0", "react-scripts": "^4.0.1", "redux": "^4.0.5" },
Code Example
hooks
import {useState} from "react"; export default function Pre04SetStateSync() { const [counter, setCounter] = useState(0) const add = () => { setCounter(counter + 1) ({counter}) } return <> <h3>synchronousSetState</h3> <p>Please observe the console</p> <button onClick={add}>counter: {counter}</button> </> }
class
export default class Pre04SetStateSync extends { state = { counter:0 } add = () => { ({counter: + 1}) ('~~',) } render() { return <> <h3>synchronousSetState</h3> <p>Please observe the console</p> <button onClick={}>counter: {}</button> </> } }
The setCounter(xxx) in the hooks structure is equivalent to setState({counter: xxx}) in the class component writing method.
You can see that the counter output immediately after setCounter(setState) is the value of the previous time, and the button is displayed correctly, indicating that this update is asynchronous (react is designed to improve performance for batch updates). The counter has not had time to change when printing. If you need to get the latest value of the counter immediately after setting, you can achieve the synchronization effect as follows.
Asynchronous writing method
1. Write in setTimeout
Note that it only applies to class components
add = () => { setTimeout(()=>{ ({counter: + 1}) ('~~',) },0) }
2. Synthetic events use native events to replace them
Note that it only applies to class components
// Native eventsexport default class Pre04SetStateSync extends { state = { counter: 0 } componentDidMount() { ('#btn').addEventListener('click', ) } add = () => { ({counter: + 1}) ('~~', ) } render() { return <> <h3>synchronousSetState</h3> <p>Please observe the console</p> <button id='btn'>counter: {}</button> </> } }
3. Write to the callback function of setState
Note that it only applies to class components
export default class Pre04SetStateSync extends { state = { counter: 0 } add = () => { ({counter: + 1}, ()=>{ ('~~', ) }) } render() { return <> <h3>synchronousSetState</h3> <p>Please observe the console</p> <button onClick={}>counter: {}</button> </> } }
4. The problem of continuous setState
Note that both class components and hooks are OK
If you change add to add 1 and then 2, you will find that the code only executes the last one plus 2, and adding 1 is ignored, such as:
const add = () => { setCounter(counter + 1) setCounter(counter + 2) }
The solution is to write the parameter of setState into a function form
const add = () => { setCounter(counter => counter + 1) setCounter(counter => counter + 2) }
5. Use side effects useEffect
Note, only for hooks
export default function Pre04SetStateSync() { const [counter, setCounter] = useState(0) const add = () => { setCounter(counter + 1) } useEffect(() => { ({counter}) }, [counter]) return <> <h3>synchronousSetState</h3> <p>Please observe the console</p> <button onClick={add}>counter: {counter}</button> </> }
Common methods for react hooks
function Example01(){ const [ count, setCount ] = useState(0) //statement return( <div> <p>{count}</p> //Read <button onClick={()=>setCount(count+1)}>count</button> // Use (modify) </div> ) }
The useEffect function will be called once for the first rendering and each rendering afterwards. Before, we had to use two lifecycle functions to represent the re-render caused by the first rendering (componentDidMonut) and the update.
The execution of functions defined in the function will not hinder the browser from updating the view, that is, these functions are executed asynchronously, while the code in componentDidMonut and componentDidUpdate are executed synchronously.
Notice:
If there is no dependency after useEffect:
In this case, every time the page update will be executed
useEffect(()=>{ ('implement'); })
If the following is empty
Execute once at the beginning of the page
useEffect(()=>{ ('implement'); },[])
If there is a value after that and is not empty
It will only be triggered when the count changes
useEffect(()=>{ ('implement'); },[count])
Use useEffect to unbind, when uninstalling components, such as clearing the timer, etc.:
However, when an empty array [] is passed, it is unbinding only when the component is to be destroyed, which implements the life cycle function of componentWillUnmount.
function Index() { useEffect(()=>{ ('useEffect=>Index') return ()=>{ ('Index page leaves') } },[]) return <h2>Test unbinding</h2>; }
Context value transmission
1. Parent component:
const CountContext = createContext() //Introducefunction Example01(){ const [ count, setCount ] = useState(0) return( <div> <p>{count}</p> <button onClick={()=>setCount(count+1)}>count</button> < value={count}> //Pass the value using the wrapping subcomponent <ChildContent/> </> </div> ) }
2. Subcomponents:
function ChildContent(){ const context = useContext(CountContext) return( <p>{context}</p> ) }
It is also a function provided by React hooks, which can enhance our reducer and implement Redux-like functions.
import React, { useReducer } from 'react' function Example5(){ const [ count, dispatch ] = useReducer((state,action)=>{ switch(action){ //Check the corresponding action and execute the corresponding method case 'add': return state+1 case 'sub': return state-1 default: return state } },1) return( <div> <p>{count}</p> <button onClick={()=>dispatch('add')}>add</button> //Through dispatch, pass the corresponding action and call the corresponding method <button onClick={()=>dispatch('sub')}>sub</button> </div> ) } export default Example5
useMemo is mainly used to solve the performance problems of useless rendering generated by using React hooks.
Only when using useMemo and then passing the second parameter to her will it be executed.
1. In the parent component, pass the corresponding required parameters
import React , {useState,useMemo} from 'react'; function Example7(){ const [one , setOne] = useState('The first state') const [two , setTwo] = useState('Chiling hospitality status') return ( <> <button onClick={()=>{setOne(new Date().getTime())}}>The first</button> <button onClick={()=>{setTwo(new Date().getTime())}}>The second one</button> <ChildComponent name={one}>{two}</ChildComponent> </> ) }
2. Parent component calls child component
function ChildComponent({name,children}){ function changeXiaohong(name){ return name } const actionXiaohong = useMemo(()=>changeXiaohong(name),[name]) return ( <> <div>{actionXiaohong}</div> <div>{children}</div> </> ) }
Use useRef to get the DOM element in React JSX, and after obtaining it, you can control anything in the DOM. However, this is not recommended. Changes in the React interface can be controlled through state
import React, { useRef } from 'react' function Example8(){ const inputRef = useRef(null) const onButtonClick=()=>{ ='THIS IS INPUT' (inputRef); } return( <div> <input type="text" ref={inputRef}/> <button onClick = {onButtonClick}>show</button> </div> ) } export default Example8
Save normal variables
import React, { useRef,useState } from 'react' function Example8(){ const inputRef = useRef(null) const onButtonClick=()=>{ ='THIS IS INPUT' (inputRef); } const [state, setstate] = useState('inputValue') //Declare a variable return( <div> <input type="text" ref={inputRef}/> <button onClick = {onButtonClick}>show</button> <input value={state} type="text" onChange={(e)=>setstate()}/> //Bind the corresponding value and bind the onChange event </div> ) } export default Example8
The above is personal experience. I hope you can give you a reference and I hope you can support me more.