1. 程式人生 > 其它 >React學習筆記 - useState解析

React學習筆記 - useState解析

引入

對於函式元件

const App = props => {
    const [n, setN] = useState(0)
    //...
}

setN執行後:

  • n不會被setN改變(重要!)
  • 會觸發UI更新,App()再次執行,再次useState(0)時,得到n的值不同

分析:

  • setNn的新值存入一箇中間變數state
  • useStatestate讀取n的最新值

模擬實現React.useState

v 1.0

用一個全域性變數_state儲存n的值

let _state
const useState2 = (initialValue)=>{
  _state = _state === undefined? initialValue: _state //判斷_state是否存在
  const setState = (newValue)=>{
    _state = newValue
    render()
  }
  return [_state, setState]
}

const render = ()=>{ //模擬實現重渲染,原始碼並非如此
    ReactDOM.render(<App />, rootElement)
}

這樣在每次呼叫useState2(0)的時候,都能使n得到最新的值。

問題:只能設定一個數據,有多個數據怎麼辦?

v 2.0

改進思路:將_state做成陣列,按順序儲存資料

let _state = []
let index = 0
const useState2 = (initialValue)=>{
	const currentIndex = index
    const setState = (newValue)=>{
        _state[currentIndex] = newValue
        render()
    }
    index++
    return [_state[currentIndex], setState]
}

const render = ()=>{
    index=0 //每次渲染前重置index
    ReactDOM.render(<App />, rootElement)
}

【陣列方案的缺陷】

每次執行App()時,設定資料的順序必須完全一樣,因此React規定useState不能用在if語句中

【目前的問題】

App元件用了_stateindex,其他元件怎麼辦?

【解決方法】

_stateindex放在元件對應的虛擬DOM上(略)

總結

  • 每個函式元件對應一個 React 節點,上面有stateindex

  • useState按其被呼叫順序讀取state[index]

  • setState會修改state,並觸發更新

問題:每次重渲染會產生新的n,怎樣才能做到每次渲染都是同一個n

如何每次使用相同的n

(重要!)在 React 中,不推薦這樣做,可以改用 Vue 3

但 React 通過某些方法也能做到,可用useRef或者useContext(存疑)

useRef

useRef常用於對元素進行引用,但也可以用於此場景,用它宣告一個數據nRef

const nRef = useRef(0) //它是一個物件:{current: 0}

useRef使得在每次重渲染時,nRef均為同一個物件,指向的地址固定。

但問題在於,對nRef進行修改不會觸發重渲染,可以再引入一個setState函式,用它強制更新

const update = useState(null)[1] //呼叫update,傳入新的值,會觸發更新

【完整示例】

const App = props => {
    const nRef = React.useRef(0)
    const update = React.useState(null)[1]
    return (
    	<div>
        	{nRef.current}
            <button onClick={()=>{
                    nRef.current++
                    update(nRef.current)
                }}>+1</button>
        </div>
    )
}

useContext

context 的特點是可以跨層級傳遞資料給後代元件。

首先建立一個context

const myContext = React.createContext(null)

然後,在<myContext.Provider></myContext.Provider>包圍的任何子元件中,都可以使用這個context

const App = props => {
  return (
    <myContext.Provider value={/* 傳入資料 */}>
        <Child />
    </myContext.Provider>
  )
}

const Child = props => {
  const a = React.useContext(myContext) //a即為以上由value傳入的資料
  return (
    <div>hi</div>
  )
}

作者:茶葉淡
連結:https://juejin.cn/post/6890086834610077704
來源:稀土掘金
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。