0
点赞
收藏
分享

微信扫一扫

路由器端口映射如何配置?

后来的六六 03-01 15:00 阅读 2

1.目标

A. 能够知道setState()更新数据是异步的
B. 能够知道JSX语法的转化过程
C. 能够说出React组件的更新机制
D. 能够对组件进行性能优化
E. 能够说出虚拟DOM和Diff算法

2.目录

A. setState()的说明
B. JSX语法的转化过程
C. 组件更新机制
D. 组件性能优化
E. 虚拟DOM和Diff算法

3.setState()的说明

3.1 更新数据

A. setState() 是异步更新数据的
B. 注意:使用该语法时,后面的setState()不能依赖于前面的setState()
C. 可以多次调用setState(),只会触发一次重新渲染
1setState.js

import React from "react";

class App31 extends React.Component {
  state = {
    count: 0,
  };
  handleClick = () => {
    //异步更新操作
    this.setState({
      count: this.state.count + 1,
    });
    console.log("count1:" + this.state.count);
    this.setState({
      count: this.state.count + 1,
    });
    console.log("count2:" + this.state.count);
  };
  render() {
    //数据更新了就会调用一次render
    //但是,如果数据变化一样的,render只调用一次
    console.log("render");
    return (
      <div>
        <h1>计数器:{this.state.count}</h1>
        <button onClick={this.handleClick}>点击</button>
      </div>
    );
  }
}

export default App31;

index,js

import App31 from "./1setState";
ReactDOM.createRoot(document.getElementById("root")).render(<App31></App31>);

3.2 推荐语法

A. 推荐:使用setState((state,props)=>{})语法
B. 参数state:表示最新的state
C. 参数props:表示最新的props

import React from "react";

class App31 extends React.Component {
  state = {
    count: 1,
  };
  handleClick = () => {
    // //异步更新操作
    // this.setState({
    //   count: this.state.count + 1,
    // });
    // console.log("count1:" + this.state.count);
    // this.setState({
    //   count: this.state.count + 1,
    // });
    // console.log("count2:" + this.state.count);

    //推荐语法
    //注意:这种语法也是异步更新state的,但是会记录最新的state的数据,所以在页面显示为3
    this.setState((state, props) => {
      console.log("state1:", state, "props1:", props);
      return {
        count: state.count + 1,
      };
    });
    console.log("count:", this.state.count); // 1

    this.setState((state, props) => {
      console.log("state2:", state, "props2:", props);
      return {
        count: state.count + 1,
      };
    });
    console.log("count:", this.state.count); // 1
  };
  render() {
    //数据更新了就会调用一次render
    //但是,如果数据变化一样的,render只调用一次
    console.log("render");
    return (
      <div>
        <h1>计数器:{this.state.count}</h1>
        <button onClick={this.handleClick}>点击</button>
      </div>
    );
  }
}

export default App31;

3.3 第二个参数

A. 场景:在状态更新(页面完成重新渲染)后立即执行某个操作
B. 语法:setState(update [,callback])

import React from "react";

class App31 extends React.Component {
  state = {
    count: 1,
  };
  handleClick = () => {
    // //异步更新操作
    // this.setState({
    //   count: this.state.count + 1,
    // });
    // console.log("count1:" + this.state.count);
    // this.setState({
    //   count: this.state.count + 1,
    // });
    // console.log("count2:" + this.state.count);
    //推荐语法
    //注意:这种语法也是异步更新state的,但是会记录最新的state的数据,所以在页面显示为3
    // this.setState((state, props) => {
    //   console.log("state1:", state, "props1:", props);
    //   return {
    //     count: state.count + 1,
    //   };
    // });
    // console.log("count:", this.state.count); // 1
    // this.setState((state, props) => {
    //   console.log("state2:", state, "props2:", props);
    //   return {
    //     count: state.count + 1,
    //   };
    // });
    // console.log("count:", this.state.count); // 1

    // 第二个参数,在状态更新(页面完成重新渲染)后立即执行某个操作
    this.setState(
      (state, props) => {
        return {
          count: state.count + 1,
        };
      },
      () => {
        console.log("状态更新完成,当前count值:", this.state.count);
      }
    );
  };
  render() {
    //数据更新了就会调用一次render
    //但是,如果数据变化一样的,render只调用一次
    console.log("render");
    return (
      <div>
        <h1>计数器:{this.state.count}</h1>
        <button onClick={this.handleClick}>点击</button>
      </div>
    );
  }
}

export default App31;

4.JSX语法的转化过程

A. JSX仅仅是createElement()方法的语法糖(简化语法)
B. JSX语法被@babel/preset-react插件编译为createElement()方法
C. React元素:是一个对象,用来描述你希望的屏幕上看到的内容
在这里插入图片描述

const element=<h1 className='greeting'>Hello JSX!</h1>
// const element1=React.createElement('h1',{
// className:'greeting'
// },'Hello JSX!!!')
console.log(element);
// console.log(element1);
ReactDOM.render(element,document.getElementById('root'))

效果图:
在这里插入图片描述

5.组件更新机制

A. setState()的两个作用:1.修改state 2.更新组件(UI)
B. 过程:父组件重新渲染时,也会重新渲染子组件。但只会渲染当前组件子树(当前组件及其所有子组件)
在这里插入图片描述
首次加载时渲染
在这里插入图片描述
点击根组件会触发所有组件,点击左侧父组件1时会触发局部更新,只更新当前组件与子组件,不会触发父组件
在这里插入图片描述
2comUpdate.js

import React from "react";
import ReactDOM from "react-dom/client";
import "./comUpdate.css";

class App50 extends React.Component {
  state = {
    bgColor: "#369",
  };
  getBgColor = () => {
    return Math.floor(Math.random() * 256);
  };
  toggleBgColor = () => {
    this.setState({
      bgColor: `rgb(${this.getBgColor()},${this.getBgColor()},${this.getBgColor()})`,
    });
  };
  render() {
    console.log("根组件");
    return (
      <div
        className="rootParent"
        style={{ backgroundColor: this.state.bgColor }}
      >
        根组件
        <button onClick={this.toggleBgColor}>切换根组件颜色</button>
        <div className="app-wrapper">
          <Parent1></Parent1>
          <Parent2></Parent2>
        </div>
      </div>
    );
  }
}
// 左边
class Parent1 extends React.Component {
  state = {
    count: 0,
  };
  handleClick = (state) => {
    this.setState((state) => {
      return {
        count: state.count + 1,
      };
    });
  };
  render() {
    console.log("左侧父组件 1");
    return (
      <div className="Parent1">
        <span>左侧-父组件</span>
        <button onClick={this.handleClick}>点击({this.state.count}</button>
        <div className="parentWrapper1">
          <Child1></Child1>
          <Child2></Child2>
        </div>
      </div>
    );
  }
}
class Child1 extends React.Component {
  render() {
    console.log("左侧子组件 1-1");
    return <div className="child1">左侧子组件1-1</div>;
  }
}
class Child2 extends React.Component {
  render() {
    console.log("左侧子组件 1-2");
    return <div className="child2">左侧子组件1-2</div>;
  }
}

// 右边
class Parent2 extends React.Component {
  state = {
    count: 0,
  };
  handleClick = (state) => {
    this.setState((state) => {
      return {
        count: state.count + 2,
      };
    });
  };
  render() {
    console.log("右侧父组件 2");
    return (
      <div className="Parent1">
        <span>右侧-父组件</span>
        <button onClick={this.handleClick}>点击({this.state.count}</button>
        <div className="parentWrapper1">
          <Child3></Child3>
          <Child4></Child4>
        </div>
      </div>
    );
  }
}
class Child3 extends React.Component {
  render() {
    console.log("右侧子组件 2-1");
    return <div className="child1">右侧子组件2-1</div>;
  }
}
class Child4 extends React.Component {
  render() {
    console.log("右侧子组件 2-2");
    return <div className="child2">右侧子组件2-2</div>;
  }
}
export default App50;

index.js

import App50 from "./2comUpdate";
ReactDOM.createRoot(document.getElementById("root")).render(<App50></App50>);

comUpdate.css

.rootParent {
  width: 800px;
  height: 600px;
  margin: 0 auto;
  font-weight: 700;
  font-size: 22px;
}

.app-wrapper {
  display: flex;
  justify-content: space-between;
  margin-top: 20px;
}

.Parent1 {
  width: 40%;
  height: 400px;
  background-color: pink;
}

.parentWrapper1 {
  display: flex;
  justify-content: space-between;
  margin-top: 30px;
}

.child1 {
  width: 40%;
  height: 300px;
  background-color: lightgreen;
}

.child2 {
  width: 40%;
  height: 300px;
  background-color: lightgrey;
}

.Parent2 {
  width: 40%;
  height: 400px;
  background-color: salmon;
}

6.组件性能优化

6.1 减轻state

A. 减轻state:只存储跟组件渲染相关的数据(比如:count/列表数据/loading等)
B. 注意:不用做渲染的数据不要放在state中,比如定时器id等
C. 对于这种需要在多个方法中用到的数据,应该放在this中

6.2 避免不要的重新渲染

A. 组件更新机制:父组件更新会引起子组件也被更新,这种思路很清晰
B. 问题:子组件没有任何变化时也会重新渲染
C. 如何避免不必要的重新渲染吗?
D. 解决方案:使用钩子函数shouldComponentUpdate(nextProps,nextState)
E. 作用:通过返回值决定该组件是否重新渲染,返回true表示重新渲染,false表示不重新渲染
F. 触发时机:更新阶段的钩子函数,组件重新渲染前执行(shouldComponentUpdate->render)
3performanceOptimize.js

import React from "react";

class App62 extends React.Component {
  state = {
    count: 0,
  };
  handleClick = () => {
    this.setState((state) => {
      return {
        count: state.count + 1,
      };
    });
  };
  //钩子函数
  shouldComponentUpdate(nextProps, nextState) {
    //返回false,阻止组件重新渲染
    // return false;
    //最新的状态
    console.log("最新的state:", nextState);
    //更新前的状态
    console.log("this.state:", this.state);
    return true;
  }
  render() {
    console.log("组件更新了");
    return (
      <div>
        <h1>count:{this.state.count}</h1>
        <button onClick={this.handleClick}>点击</button>
      </div>
    );
  }
}

export default App62;

index.js

import App62 from "./3performanceOptimize";
ReactDOM.createRoot(document.getElementById("root")).render(<App62></App62>);

6.2.1 案例:随机数(nextState)

4App621Random.js

import React from "react";

class App621Random extends React.Component {
  state = {
    number: 0,
  };
  getRandom = () => {
    this.setState((state) => {
      return {
        number: Math.floor(Math.random() * 3),
      };
    });
  };
  //因为两次生成的随机数可能相同,如果相同,此时,不需要重新渲染
  shouldComponentUpdate(nextProps, nextState) {
    if (nextState.number === this.state.number) {
      return false;
    }
    return true;
  }
  render() {
    console.log("触发渲染");
    return (
      <div>
        <h1>随机数:{this.state.number}</h1>
        <button onClick={this.getRandom}>获取随机数</button>
      </div>
    );
  }
}

export default App621Random;

index.js

import App621Random from "./4App621Random";
ReactDOM.createRoot(document.getElementById("root")).render(
  <App621Random></App621Random>
);

6.2.2 案例:随机数(NextProps)

4App621Random.js

import React from "react";

class App621Random extends React.Component {
  state = {
    number: 0,
  };
  getRandom = () => {
    this.setState((state) => {
      return {
        number: Math.floor(Math.random() * 3),
      };
    });
  };
  //因为两次生成的随机数可能相同,如果相同,此时,不需要重新渲染
  // shouldComponentUpdate(nextProps, nextState) {
  //   if (nextState.number === this.state.number) {
  //     return false;
  //   }
  //   return true;
  // }
  render() {
    console.log("触发父组件的render");
    return (
      <div>
        {/* <h1>随机数:{this.state.number}</h1> */}
        <ChildNumber number={this.state.number}></ChildNumber>
        <button onClick={this.getRandom}>获取随机数</button>
      </div>
    );
  }
}
class ChildNumber extends React.Component {
  shouldComponentUpdate(nextProps, nextState) {
    console.log("最新props:", nextProps, ",当前props:", this.props);
    return nextProps.number !== this.props.number;
  }
  render() {
    console.log("子组件中的render");
    return <h1>子组件的随机数:{this.props.number}</h1>;
  }
}

export default App621Random;

index.js

import App621Random from "./4App621Random";
ReactDOM.createRoot(document.getElementById("root")).render(
  <App621Random></App621Random>
);

6.3 纯组件

A. 纯组件:PureComponent与React.Component功能相似
B. 区别:PureComponent内部自动实现了shouldComponentUpdate钩子,无需手动比较
C. 原理:纯组件内部通过对比前后两次props和state的值,来决定是否重新渲染组件
5pure.js

import React from "react";

class PureApp extends React.PureComponent {
  state = {
    number: 0,
  };
  getRandom = () => {
    this.setState((state) => {
      return {
        number: Math.floor(Math.random() * 2),
      };
    });
  };
  render() {
    console.log("父组件render");
    return (
      <div>
        <h1>父组件随机数:{this.state.number}</h1>
        <ChildPure number={this.state.number}></ChildPure>
        <button onClick={this.getRandom}>获取随机数</button>
      </div>
    );
  }
}

class ChildPure extends React.PureComponent {
  render() {
    console.log("子组件render");
    return <h1>子组件随机数:{this.props.number}</h1>;
  }
}
export default PureApp;

index.js

import PureApp from "./5pure";
ReactDOM.createRoot(document.getElementById("root")).render(
  <PureApp></PureApp>
);

6.3.1 浅层对比

A. 说明:纯组件内部的对比是shallow compare(浅层对比)
B. 对于值类型来说:比较两个值是否相同(直接赋值即可,没有坑)
C.对于引用类型来说:只比较对象的引用(地址)是否相同
D.注意:state或props中属性值为引用类型时,应该创建新数据,不要直接修改数据!
shallow.js

import React from "react";

class ShallowRandom extends React.PureComponent {
  state = {
    obj: {
      number: 0,
    },
  };
  getRandom = () => {
    // 错误演示:直接修改原始对象中属性的值
    // const newObj = this.state.obj;
    // newObj.number = Math.floor(Math.random() * 2);
    // this.setState((state) => {
    //   return {
    //     obj: newObj,
    //   };
    // });

    //正确做法:创建新对象
    const newObj = { ...this.state.obj, number: Math.floor(Math.random() * 2) };
    this.setState(() => {
      return {
        obj: newObj,
      };
    });
  };
  render() {
    console.log("父组件render");
    return (
      <div>
        <h1>父组件随机数的值:{this.state.obj.number}</h1>
        <ChildRandom number={this.state.obj.number}></ChildRandom>
        <button onClick={this.getRandom}>重新生成随机数</button>
      </div>
    );
  }
}

class ChildRandom extends React.PureComponent {
  render() {
    console.log("子组件render");
    return <h1>子组件随机数:{this.props.number}</h1>;
  }
}

export default ShallowRandom;
import ShallowRandom from "./6shallow";
ReactDOM.createRoot(document.getElementById("root")).render(
  <ShallowRandom></ShallowRandom>
);

7.虚拟DOM和DIFF算法

A. React更新视图的思路是:只是state变化就重新渲染视图
B. 特点:思路非常清晰
C. 问题:组件中只有一个DOM元素需要更新时,也得把整个组件的内容重新渲染到页面中?不是
D. 理想状态:部分更新,只更新变化的地方
E. 问题:React是如何做到部分更新的?虚拟DOM配合Diff算法
F. 虚拟DOM:本质上就是一个JS对象,用来描述你希望在屏幕上看到的内容(UI)
在这里插入图片描述

7.1 执行过程

A. 初次渲染时,React会根据初始state(Model),创建一个虚拟DOM对象(树)。
B. 根据虚拟DOM生成真正的DOM,渲染到页面中
C. 当数据变化后(setState()),重新根据新的数据,创建新的虚拟DOM对象(树)
在这里插入图片描述
A. 与上一次得到的虚拟DOM对象,使用Diff算法对比(找不同),得到需要更新的内容
B. 最终,React只将变化的内容更新(patch)到DOM中,重新渲染到页面
在这里插入图片描述

7.2 代码演示

A. 组件render()调用后,根据状态和JSX结构生成虚拟DOM对象
B. 示例中,只更新P元素的文本节点内容
7.vdom.js

import React from "react";

class Vdom extends React.PureComponent {
  state = {
    number: 0,
  };
  getRandom = () => {
    this.setState(() => {
      return {
        number: Math.floor(Math.random() * 3),
      };
    });
  };
  render() {
    return (
      <div>
        <h1>随机数</h1>
        <h1>{this.state.number}</h1>
        <button onClick={this.getRandom}>重新生成</button>
      </div>
    );
  }
}

export default Vdom;

index.js

import Vdom from "./7vdom";
ReactDOM.createRoot(document.getElementById("root")).render(<Vdom></Vdom>);

8.总结

A. 工作角度:应用第一,原理第二
B. 原理有助于更好的理解React的自身运行机制
C. SetState()异步更新数据
D. 父组件更新导致子组件更新,纯组件提升性能
E. 思路清晰简单为前提,虚拟DOM和Diff保效率
F. 虚拟DOM->state+JSX
G. 虚拟DOM的真正价值从来都不是性能
H. 虚拟DOM使react脱离了浏览器的束缚

举报

相关推荐

0 条评论