setState
App
會被調用,獲得虛擬dom
,建立真實的dom
button
時,調用setN
,再次調用App
,獲得虛擬dom
,用DOM Diff
算法更新dom
import React from "react"; import ReactDOM from "react-dom"; const rootElement = document.getElementById("root"); function App() { const [n, setN] = React.useState(0); console.log("App 運行了"); // App 被調用就會執行一次 console.log(`n: ${n}`); // App 被調用後 n 每次都不同 return ( <div className="App"> <p>{n}</p> <p> <button onClick={() => setN(n + 1)}>+1</button> </p> </div> ); } ReactDOM.render(<App />, rootElement);
n
在App
被調用後每次都會變化,可是setN()
卻不會改變n
。react
setN
必定會修改數據x
,將n + 1
存入x
setN
必定會觸發App
從新渲染`useState
確定會從x
讀取n
的最新值x
,咱們將其命名成state
setState
myUseState
,接收一個初始值initialValue
initialValue
賦值給一箇中間變量state
setState
,接收一個newValue
,再將newValue
賦值給state
,並執行App
state
和setState
import React from "react"; import ReactDOM from "react-dom"; const rootElement = document.getElementById("root"); const myUseState = initialValue => { let state = initialValue; const setState = newValue => { state = newValue; render(); }; return [state, setState]; }; const render = () => { ReactDOM.render(<App />, rootElement); }; function App() { const [n, setN] = myUseState(0); return ( <div className="App"> <p>{n}</p> <p> <button onClick={() => setN(n + 1)}>+1</button> </p> </div> ); } ReactDOM.render(<App />, rootElement);
可是這樣有個問題每次執行setN
時,都會把state
設置爲初始值,由於每次執行setN
都會傳入一個初始值0
算法
解決這個問題就是將state
變成全局變量數組
import React from "react"; import ReactDOM from "react-dom"; const rootElement = document.getElementById("root"); let _state; const myUseState = initialValue => { _state = _state === undefined ? initialValue : _state; const setState = newValue => { _state = newValue; render(); }; return [_state, setState]; }; const render = () => { ReactDOM.render(<App />, rootElement); }; function App() { const [n, setN] = myUseState(0); return ( <div className="App"> <p>{n}</p> <p> <button onClick={() => setN(n + 1)}>+1</button> </p> </div> ); } ReactDOM.render(<App />, rootElement);
useState
function App() { const [n, setN] = myUseState(0); const [M, setM] = myUseState(1); // 會出問題,第一個會被覆蓋 return ( <div className="App"> <p>{n}</p> <p> <button onClick={() => setN(n + 1)}>+1</button> </p> <p>{m}</p> <p> <button onClick={() => setM(m + 1)}>+1</button> </p> </div> ); }
因爲全部數據都存在一個_state
中,因此會衝突。微信
可使用數組去解決_state
重複問題。dom
_state
聲明爲[]
,同時聲明一個索引index = 0
myUseState
方法內部聲明一個臨時變量currentIndex
,用來保存索引index
_state
setState
時也將經過索引去操做_state
index += 1
_state[currentIndex]
和setState
render
方法是將index
重置爲0
import React from "react"; import ReactDOM from "react-dom"; const rootElement = document.getElementById("root"); let _state = []; let index = 0; const myUseState = initialValue => { const currentIndex = index; _state[currentIndex] = _state[currentIndex] === undefined ? initialValue : _state[currentIndex]; const setState = newValue => { _state[currentIndex] = newValue; render(); }; index += 1; return [_state[currentIndex], setState]; }; const render = () => { index = 0; ReactDOM.render(<App />, rootElement); }; function App() { const [n, setN] = myUseState(0); const [m, setM] = myUseState(0); return ( <div className="App"> <p>{n}</p> <p> <button onClick={() => setN(n + 1)}>N+1</button> </p> <p>{m}</p> <p> <button onClick={() => setM(m + 1)}>M+1</button> </p> </div> ); } ReactDOM.render(<App />, rootElement);
useState
調用順序n
是第一個,m
是第二個,k
是第三個React
不容許出現以下代碼function App() { const [n, setN] = myUseState(0); let m, setM; if (n % 2 === 1) [m, setM] = myUseState(0); // 報錯 return ( <div className="App"> <p>{n}</p> <p> <button onClick={() => setN(n + 1)}>N+1</button> </p> <p>{m}</p> <p> <button onClick={() => setM(m + 1)}>M+1</button> </p> </div> ); }
報錯信息:React has detected a change in the order of Hooks called by App. This will lead to bugs and errors if not fixed.
函數
App
用了_state
和index
那其餘組件用什麼?post
_state
和index
放在全局做用域重名了咋整code
bug
function App() { const [n, setN] = myUseState(0); const log () => setTimeout(() => console.log(`n: ${n}`), 3000) return ( <div className="App"> <p>{n}</p> <p> <button onClick={() => setN(n + 1)}>N+1</button> <button onClick={log}>log</button> </p> </div> ); }
先點擊N+1
時,再點擊log
,輸出是沒有問題對象
若是先點擊log
,在點擊N+1
,就會發現輸出的竟然是0
。難道N+1
後輸出不是1
麼。索引
由於setN
是不會改變n
,而是生成一個新的n
。
bug
window.xxx
useRef
不只能夠用於div
,還能用於任意數據useContext
不能能貫穿始終,還能貫穿不一樣組件function App() { const nRef = React.useRef(0); // { current: 0 } const log () => setTimeout(() => console.log(`n: ${React.useRef(0)}`), 3000); const update = React.useState(null)[1]; return ( <div className="App"> <p>{nRef.current}</p> <p> <button onClick={() => { nRef.current += 1; // 這裏不能實時更新 update(nRef.current; )}}>N+1</button> <button onClick={log}>log</button> </p> </div> ); }
React.current += 1
不會讓App
從新渲染。
React
節點state
和index
useState
會讀取state[index]
index
由useState
出現的順序決定setState
會修改state
,並觸發更新。Tips
:
React
作了簡化,方便理解。React
對象節點應該是FiberNode
_state
的真實名稱爲memorizedState
;index
的實現用到了鏈表 另外可添加微信ttxbg180218
交流