最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 【React全解3】React.useState原理详解,一次性搞懂useState

    正文概述 掘金(soloplayer)   2020-12-14   627

    目录

    • 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、最终效果呈现

    【React全解3】React.useState原理详解,一次性搞懂useState

    三、手写实现 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会直接报错 */
    

    【React全解3】React.useState原理详解,一次性搞懂useState

    • 每个组件命名的问题

    App用了_state和index,那其他组件用什么?放在全局作用域重名了怎么办?

    解决办法1:每个组件都创建一个_state和index。

    解决办法2:放在组件对应的虚拟节点对象上

    注意

    React的节点应该是FiberNode,_state的真实名称为memorizedState,index的实现使用了链表。

    五、参考

    React Hooks原理 React官网


    起源地下载网 » 【React全解3】React.useState原理详解,一次性搞懂useState

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元