目录
useState简介
useState的简单使用
手写实现useState
总结
参考
一、useState 简介
二、useState 的简单使用
1、在类组件中使用 useState
class Classes extends React.Component {
constructor(props) {
super(props);
this.state = {
n: 0,
};
}
add() {
this.setState({ n: this.state.n + 1 });
}
render() {
return (
<div className="son">
类组件--n:{this.state.n}
<button onClick={() => this.add()}>+1</button>
<Functions />
</div>
);
}
}
2、在函数组件中使用 useState
const Functions = () => {
const [n, setN] = React.useState(0);
return (
<div className="grandson">
函数组件--n:{n}
<button onClick={() => setN(n + 1)}>+1</button>
</div>
);
};
3、App 组件
function App() {
return (
<div className="app">
useState的简单使用
<Classes />
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
4、最终效果呈现
三、手写实现 useState
1、分析
-
useState 有两个状态,一个是 n,另外一个是 setN。
-
setN 是修改数据 n 的,将修改后的 n 存入 state。
-
setN 修改数据后一定会触发<App/>的重新渲染(re-render)。
-
useState 一定会从 state 读取最新的 n 值。
-
每个组件都有自己的数据 state。
2、尝试实现 React.useState
第1次写myUseState
function myUseState(initialValue) {
let state = initialValue;
const setState = (newValue) => {
state = newValue; //更新state值,
render(); //触发重新渲染
};
return [state, setState];
}
/* 粗糙的渲染 */
const render = () => {
ReactDOM.render(<App />, document.getElementById("root"));
};
// 使用myUseState
const App = () => {
const [n, setN] = myUseState(0);
return (
<div classNam="App">
<p>n:{n}</p>
<button onClick={()=>{setN(n+1)}}>n+1</button>
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
第一次总结
运行第一次写的myUseState时发现,页面完全没有变化。n值也没有发生改变。经分析,是因为每次调用myUseState时会重置state的值
。经过改进,必须将state写在函数的外面
。
第2次写myUseState
let _state;
function myUseState(initialValue) {
_state = _state===undefined? initialValue:_state;
const setState = (newValue) => {
_state = newValue; //更新state值,
render(); //触发重新渲染
};
return [_state, setState];
}
/* 粗糙的渲染 */
const render = () => {
ReactDOM.render(<App />, document.getElementById("root"));
};
// 使用myUseState
const App = () => {
const [n, setN] = myUseState(0);
return (
<div classNam="App">
<p>n:{n}</p>
<button onClick={()=>{setN(n+1)}}>n+1</button>
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
第二次总结
运行成功,页面中的n发生了变化!
但是问题又来了,如果一个组件用了两个useState
怎么办?_state的值不是会发生冲突吗?继续改进完善myUseState。将_state做成数组
。
第3次写myUseState
let _state=[];
let index=0;
function myUseState(initialValue) {
int currentIndex=index; //引入中间变量currentIndex就是为了保存当前操作的下标index。
_state[currentIndex] = _state[currentIndex]===undefined? initialValue:_state[currentIndex];
const setState = (newValue) => {
_state[currentIndex] = newValue;
render();
};
index+=1;// 每次更新完state值后,index值+1
return [_state[currentIndex], setState];
}
const render = () => {
index=0; //重要的一步,必须在渲染前后将index值重置为0,不然index会一种增加1
ReactDOM.render(<App />, document.getElementById("root"));
};
// 使用myUseState
const App = () => {
const [n, setN] = myUseState(0);
const [m, setM] = myUseState(0);
return (
<div classNam="App">
<p>n:{n}</p>
<button onClick={()=>{setN(n+1)}}>n+1</button>
<p>m:{m}</p>
<button onClick={()=>{setM(m+1)}}>n+1</button>
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
第三次总结
运行成功!n,m值都能单独的发生变化。
四、总结
useState调用顺序
若第一次渲染的时候,n是第一个数据,m是第二个数据,k是第三个。...
则第二次渲染的时候必须保证完全的一致。
React不允许出现以下类似的代码,否则会出现报错信息:React Hook "React.useState" is called conditionally. React Hooks must be called in the exact same order in every component render react-hooks/rules-of-hooks
译:有条件地调用React Hook“ React.useState”。在每个组件中,必须以完全相同的顺序调用React Hooks来渲染react-hooks / rules-of-hooks
let n=2;
if(n%2){
const [m,setM]=React.useState(0);
}
/* 以上代码React会直接报错 */
每个组件命名的问题
App用了_state和index,那其他组件用什么?放在全局作用域重名了怎么办?
解决办法1:每个组件都创建一个_state和index。
解决办法2:放在组件对应的虚拟节点对象上
注意
:
React的节点应该是FiberNode,_state的真实名称为memorizedState,index的实现使用了链表。
五、参考
React Hooks原理 React官网
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!