useState
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不允许出现如下代码
总结
- 每个函数组件对应一个
React节点 - 每个节点保存着
state和index(这个state可能描述不准确,但主要是让大家想清楚这个事情,应该是一个类似state的东西) useState会读取state[index]index由useState出现的顺序决定setState会修改State,并触发更新