react中(含hooks)同步獲取state值的方式
react(含hooks)同步獲取state值
環(huán)境
"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" ? },
代碼示例
hooks
import {useState} from "react"; export default function Pre04SetStateSync() { ? ? const [counter, setCounter] = useState(0) ? ? const add = () => { ? ? ? ? setCounter(counter + 1) ? ? ? ? console.log({counter}) ? ? } ? ? return <> ? ? ? ? <h3>同步SetState</h3> ? ? ? ? <p>請觀察控制臺</p> ? ? ? ? <button onClick={add}>counter: {counter}</button> ? ? </> }
class
export default class Pre04SetStateSync extends React.Component{ ? ? state = { ? ? ? ? counter:0 ? ? } ? ? add = () => { ? ? ? ? this.setState({counter:this.state.counter + 1}) ? ? ? ? console.log('~~this.state.counter',this.state.counter) ? ? } ? ? render() { ? ? ? ? return <> ? ? ? ? ? ? <h3>同步SetState</h3> ? ? ? ? ? ? <p>請觀察控制臺</p> ? ? ? ? ? ? <button onClick={this.add}>counter: {this.state.counter}</button> ? ? ? ? </> ? ? } }
hooks結(jié)構(gòu)中的setCounter(xxx)相當(dāng)于class組件寫法中setState({counter: xxx})
可以對比控制臺看到,這樣直接setCounter(setState)后立即輸出的counter的是上一次的值,而按鈕上顯示正確,說明本次更新是異步的(react這樣設(shè)計是為了批量更新而提高性能),打印時counter還沒來得及改變。如果需要set完后立即取到counter的最新值,可以按如下方法實現(xiàn)同步的效果。
異步寫成同步的方法
1. 寫在setTimeout中
注意,只適用于class組件
add = () => { ? ? setTimeout(()=>{ ? ? ? ? this.setState({counter:this.state.counter + 1}) ? ? ? ? console.log('~~this.state.counter',this.state.counter) ? ? },0) }
2. 合成事件使用原生事件替代
注意,只適用于class組件
// 原生事件 export default class Pre04SetStateSync extends React.Component { ? ? state = { ? ? ? ? counter: 0 ? ? } ? ? componentDidMount() { ? ? ? ? document.querySelector('#btn').addEventListener('click', this.add) ? ? } ? ? add = () => { ? ? ? ? this.setState({counter: this.state.counter + 1}) ? ? ? ? console.log('~~this.state.counter', this.state.counter) ? ? } ? ? render() { ? ? ? ? return <> ? ? ? ? ? ? <h3>同步SetState</h3> ? ? ? ? ? ? <p>請觀察控制臺</p> ? ? ? ? ? ? <button id='btn'>counter: {this.state.counter}</button> ? ? ? ? </> ? ? } }
3. 寫入setState的回調(diào)函數(shù)中
注意,只適用于class組件
export default class Pre04SetStateSync extends React.Component { ? ? state = { ? ? ? ? counter: 0 ? ? } ? ? add = () => { ? ? ? ? this.setState({counter: this.state.counter + 1}, ()=>{ ? ? ? ? ? ? console.log('~~this.state.counter', this.state.counter) ? ? ? ? }) ? ? } ? ? render() { ? ? ? ? return <> ? ? ? ? ? ? <h3>同步SetState</h3> ? ? ? ? ? ? <p>請觀察控制臺</p> ? ? ? ? ? ? <button onClick={this.add}>counter: {this.state.counter}</button> ? ? ? ? </> ? ? } }
4. 連續(xù)setState的問題
注意,class組件和hooks都可以
如果將add改為先加1再加2,會發(fā)現(xiàn)代碼只執(zhí)行了最后一個加2,加1被忽略了,如:
const add = () => { ? ? setCounter(counter + 1) ? ? setCounter(counter + 2) }
解決方法是將setState的參數(shù)寫成函數(shù)形式
const add = () => { ? ? setCounter(counter => counter + 1) ? ? setCounter(counter => counter + 2) }
5. 使用副作用useEffect
注意,只適用于hooks
export default function Pre04SetStateSync() { ? ? const [counter, setCounter] = useState(0) ? ? const add = () => { ? ? ? ? setCounter(counter + 1) ? ? } ? ? useEffect(() => { ? ? ? ? console.log({counter}) ? ? }, [counter]) ? ?? ? ? return <> ? ? ? ? <h3>同步SetState</h3> ? ? ? ? <p>請觀察控制臺</p> ? ? ? ? <button onClick={add}>counter: {counter}</button> ? ? </> }
react hooks常用方法
1.useState
function Example01(){ ? ? const [ count, setCount ] = useState(0) ?//聲明 ? ? return( ? ? ? ? <div> ? ? ? ? ? ? <p>{count}</p> ?//讀取 ? ? ? ? ? ? <button onClick={()=>setCount(count+1)}>計數(shù)</button> // 使用(修改) ? ? ? ? </div> ? ? ) }
2.useEffect
1.React首次渲染和之后的每次渲染都會調(diào)用一遍useEffect函數(shù),而之前我們要用兩個生命周期函數(shù)分別表示首次渲染(componentDidMonut)和更新導(dǎo)致的重新渲染(componentDidUpdate)
2.useEffect中定義的函數(shù)的執(zhí)行不會阻礙瀏覽器更新視圖,也就是說這些函數(shù)時異步執(zhí)行的,而componentDidMonut和componentDidUpdate中的代碼都是同步執(zhí)行的。
注意:
如果useEffect后面沒有依賴:
這種時候每次每次頁面更新都會執(zhí)行
useEffect(()=>{ ? ? console.log('執(zhí)行'); })
如果后面為空
頁面初始的時候執(zhí)行一次
useEffect(()=>{ ? ? console.log('執(zhí)行'); },[])
如果后面有值且不為空
只有當(dāng)count改變時才會被觸發(fā)
useEffect(()=>{ ? ? console.log('執(zhí)行'); },[count])
使用useEffect解綁,組件卸載的時候,比如需要清除計時器等:
但是當(dāng)傳空數(shù)組[]時,就是當(dāng)組件將被銷毀時才進行解綁,這也就實現(xiàn)了componentWillUnmount的生命周期函數(shù)。
function Index() { ? ? useEffect(()=>{ ? ? ? ? console.log('useEffect=>Index') ? ? ? ? return ()=>{ ? ? ? ? ? ? console.log('Index頁面離開') ? ? ? ? } ? ? },[]) ? ? return <h2>測試解綁</h2>; }
3.useContext上下文傳值
1.父組件:
const CountContext = createContext() ?//引入 function Example01(){ ? ? const [ count, setCount ] = useState(0) ? ? return( ? ? ? ? <div> ? ? ? ? ? ? <p>{count}</p> ? ? ? ? ? ? <button onClick={()=>setCount(count+1)}>計數(shù)</button> ? ? ? ? ? ? <CountContext.Provider value={count}> ?//使用包裹子組件傳遞值 ? ? ? ? ? ? ? ? <ChildContent/> ? ? ? ? ? ? </CountContext.Provider> ? ? ? ? ? ? ? </div> ? ? ) }
2.子組件:
function ChildContent(){ ? ? ?const context = useContext(CountContext)? ? ? ?return( ? ? ? ? ?<p>{context}</p> ? ? ?) }
4.useReducer
它也是React hooks提供的函數(shù),可以增強我們的Reducer,實現(xiàn)類似Redux的功能。
import React, { useReducer ?} from 'react' function Example5(){ ? ? const [ count, dispatch ] = useReducer((state,action)=>{ ? ? ? ? ? ? ? ? switch(action){ ? //通過判斷對應(yīng)的action,去執(zhí)行對應(yīng)的方法 ? ? ? ? ? ? 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> ?//通過dispatch,傳遞對應(yīng)的action,調(diào)用對應(yīng)的方法 ? ? ? ? ? ? <button onClick={()=>dispatch('sub')}>sub</button> ? ? ? ? </div> ? ? ) } export default Example5
5.useMemo
useMemo主要用來解決使用React hooks產(chǎn)生的無用渲染的性能問題。
只要使用useMemo,然后給她傳遞第二個參數(shù),參數(shù)匹配成功,才會執(zhí)行。
1.在父組件里面,傳遞對應(yīng)需要的參數(shù)
import React , {useState,useMemo} from 'react'; function Example7(){ ? ? const [one , setOne] = useState('第一個的狀態(tài)') ? ? const [two , setTwo] = useState('志玲待客狀態(tài)') ? ? return ( ? ? ? ? <> ? ? ? ? ? ? <button onClick={()=>{setOne(new Date().getTime())}}>第一個</button> ? ? ? ? ? ? <button onClick={()=>{setTwo(new Date().getTime())}}>第二個</button> ? ? ? ? ? ? <ChildComponent name={one}>{two}</ChildComponent> ? ? ? ? </> ? ? ) }
2.父組件調(diào)用子組件
function ChildComponent({name,children}){ ? ? function changeXiaohong(name){ ? ? ? ? return name ? ? } ?const actionXiaohong = useMemo(()=>changeXiaohong(name),[name]) ? ? return ( ? ? ? ? <> ? ? ? ? ? ? <div>{actionXiaohong}</div> ? ? ? ? ? ? <div>{children}</div> ? ? ? ? </> ? ? ) }
6.useRef
用useRef獲取React JSX中的DOM元素,獲取后你就可以控制DOM的任何東西了。但是一般不建議這樣來作,React界面的變化可以通過狀態(tài)來控制
import React, { useRef } from 'react' function Example8(){ ? ? const inputRef ?= useRef(null) ? ? const onButtonClick=()=>{ ? ? ? ? inputRef.current.value='THIS IS INPUT' ? ? ? ? console.log(inputRef); ? ? } ? ? return( ? ? ? ? <div> ? ? ? ? ? ? <input type="text" ref={inputRef}/> ? ? ? ? ? ? <button onClick = {onButtonClick}>顯示</button> ? ? ? ? </div> ? ? ) } export default Example8
保存普通變量
import React, { useRef,useState } from 'react' function Example8(){ ? ? const inputRef ?= useRef(null) ? ? const onButtonClick=()=>{ ? ? ? ? inputRef.current.value='THIS IS INPUT' ? ? ? ? console.log(inputRef); ? ? } ? ? ?const [state, setstate] = useState('inputValue') ?//聲明一個變量 ? ? return( ? ? ? ? <div> ? ? ? ? ? ? <input type="text" ref={inputRef}/> ? ? ? ? ? ? <button onClick = {onButtonClick}>顯示</button> ? ? ? ? ? ? <input value={state} type="text" onChange={(e)=>setstate(e.target.value)}/> ?//綁定對應(yīng)的值以及綁定onChange事件 ? ? ? ? </div> ? ? ) } export default Example8
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
react組件中的constructor和super知識點整理
這篇文章主要介紹了react組件中的constructor和super知識點整理,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-08-08淺談webpack+react多頁面開發(fā)終極架構(gòu)
這篇文章主要介紹了淺談webpack+react多頁面開發(fā)終極架構(gòu),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-11-11React Router V5:使用HOC組件實現(xiàn)路由攔截功能
這篇文章主要介紹了React Router V5:使用HOC組件實現(xiàn)路由攔截功能,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-03-03