useState用法
脑补一下点击button后会发生什么
function App() { const [n, setN] = React.useState(0); return ( <div className="App"> <p>{n}</p> <p> <button onClick={() => setN(n + 1)}>+1</button> </p> </div> ); }
会使页面上的n
变量由0变成1
脑补之后
问自己几个问题
执行setN
的时候会发生什么?n会变吗?App()会重新执行吗?
如果App()会重新执行,那么useState(0)
的时候,n每次的值会有不同吗?
通过console.log
你就能得到答案
分析
setN
setN
一定会修改数据x
,(我们暂且将这个不知道的东西称为x),将n+1
存入x
setN
一定会触发<App/>
重新渲染(render
)
useState
useState
肯定会从x
读取到n
的最新值
x
每个组件有自己的数据x
,我们将其命名为state
尝试实现React.useState
function myUseState(initialValue) { var state = initialValue; function setState(newState) { state = newState; render(); } return [state, setState]; } // render方法我们就不实现了,直接让它渲染 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> ); }
完全没有变化啊
因为myUseState
会将state
重置
我们需要一个不会被myUseState
重置的变量
那么这个变量只要声明在myUseState
外面即可
// *********************************** let _state; // *********************************** function myUseState(initialValue) { _state = _state === undefined ? initialValue : _state; function setState(newState) { _state = newState; 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> ); }
useState就这么简单?
别急,还有问题
如果一个组件用了两个useState怎么办?
由于所有数据都方在_state,所以会冲突
改进思路
把_state做成一个对象
比如_state = { n:0, m:0}
不行,因为useState(0)
并不知道变量叫n
还是m
把_state做成数组
比如_state= [ 0, 0 ]
貌似可行,我们来试试看
多个useState
// *********************************** let _state = []; let index = 0; // *********************************** function myUseState(initialValue) { const currentIndex = index; index += 1; _state[currentIndex] = _state[currentIndex] || initialValue; const setState = newState => { _state[currentIndex] = newState; render(); }; return [_state[currentIndex], setState]; } const render = () => { index = 0; ReactDOM.render(<App />, rootElement); }; function App() { const [n, setN] = myUseState(0); const [m, setM] = myUseState(0); console.log(_state); 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数组方案缺点
useState调用顺序
如果第一次渲染时,n是第一个,m是第二个,k是第三个
则第二次渲染时必须保证顺序完全一致
所以React不允许出现如下代码
2 ReactDOM . render (< cApp />, rootElement ): 25 Function App (){ const [ n , setN ] React . useState (0); let m , setM ; if ( n %2-1) [ m , setM ]= React . useState (0): return ( cdiv className -" App ">< p > fnj </ p > < button onC1ick={()=> setN ( n .1))>+1</ button >
Console wos cleored Uncaught Invariant Violation : Rendered more hooks than during the previous render . invariant (https://j6y72.csb.anp/no odules / react - dom / cjs / react - dom . develonment . js :55:15) updateworkinProgressHook (httR5i/Z1by72.csb. anp / node moduies / react - gon /c3sreact- gom . oeveopn updateReducer (https://16y72.csb.app/nodem modu1es/ react - dom /c1s/ react - dom .deye1ooment.1s1139991 nt .1s:13294:10)
总结
- 每个函数组件对应一个
React
节点 - 每个节点保存着
state
和index
(这个state可能描述不准确,但主要是让大家想清楚这个事情,应该是一个类似state的东西) useState
会读取state[index]
index
由useState
出现的顺序决定setState
会修改State
,并触发更新