React-组件原理

setState原理

setState()是异步更新数据的
注意:使用该语法的时候,后面的 setState()不要依赖于前面的setState()
可以多次调用setState(),只会触发一次重新渲染
复制代码
import React from 'react';
import { createRoot } from 'react-dom/client';
class App1 extends React.Component {
  state = {
    count: 1
  }
  handelClick = () => {
    //此处,更新state
    //注意:异步更新数据的
    this.setState({
      count: this.state.count + 1
    })
    console.log('count', this.state.count);//1
  }
  render() {
    console.log('render');
    return (

      <div>
        <h1>计数器:{this.state.count}</h1>
        <button onClick={this.handelClick}>+1</button>
      </div>
    )
  }
}
const container = document.getElementById('root');
const root = createRoot(container);
root.render(<App1 />);
复制代码

setstate推荐语法

this.setState((state, props) => {
      return {
        count: state.count + 1
      }
    })
第二个参数的使用
场景:在状态更新(页面完成重新渲染)后立即执行某个操作
复制代码
handelClick = () => {
    this.setState((state, props) => {
      return {
        count: state.count + 1
      }
    }, () => {
      console.log('状态更新完成', this.state.count);//2
      console.log(document.getElementById('title').innerText);
      document.title = "更新标题" + this.state.count
    }
    )
    console.log('count', this.state.count);//1
  }
复制代码

JSX语法的转化过程

 

 

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

组件更新机制

setState的作用
  1. 修改state
  2. 更新组件(UI)
过程:父组件重新渲染时,也会重新渲染子组件。但只会渲染当前组件子树(当前组件及其所有子组件)
 

组件性能优化

1.减轻state

只存储和组件渲染相关的数据(比如:count/列表数据/loading等)
注意:不用做渲染的数据不要放在state中,比如定时器id等
对于这种需要在多个方法中使用到的数据,应该放在this中
 
 
2.避免不必要的重新渲染
组件更新机制:父组件更新会引起子组件也被更新
问题:子组件没有任何变化时也会重新渲染
如何避免不必要的重新渲染呢?
解决方式:使用钩子函数shouldComponentUpdate(nextProps,nextState)
作用:通过返回值决定该组件是否重新渲染,返回true表示重新渲染,false表示不重新渲染
触发实际:更新阶段的钩子函数,组件重新渲染前执行,render执行前执行
复制代码
class App extends React.Component {
  state = {
    count: 0
  }
  handleClick = () => {
    this.setState((state) => {
      return {
        count: state.count + 1
      }
    })
  }
  shouldComponentUpdate = (nextProps, nextState) => {
    //返回false,阻止组件重新渲染
    // return false
    //最新的状态
    console.log('最新的count', nextState);
    //更新前的状态
    console.log('更新前的状态', this.state);
    return true
  }
  //钩子函数
  render() {
    console.log('组件更新了');
    return (
      <div>
        <h1>计数器:{this.state.count}</h1>
        <button onClick={this.handleClick}>+1</button>
      </div>
    )
  }
}
const container = document.getElementById('root')
const root = createRoot(container)
root.render(<App />)
复制代码

案例:随机数案例

复制代码
//随机数
class App extends React.Component {
  state = {
    count: 0
  }
  handleClick = () => {
    this.setState(() => {
      return {
        count: Math.floor(Math.random() * 3)
      }
    })
  }
  //因为两次生成的随机数可能相同,所以,此时不需要重新渲染
  shouldComponentUpdate(nextProps, nextState) {
    console.log('最新状态:', nextState, '当前状态:', this.state);
    if (nextState.count === this.state.count) {
      return false
    }
    return true
  }
  render() {
    console.log('render');
    return (
      <div>
        <h1>随机数:{this.state.count}</h1>
        <button onClick={this.handleClick}>重新生成</button>
      </div>
    )
  }
}
const container = document.getElementById('root')
const root = createRoot(container)
root.render(<App />)
复制代码
复制代码
//随机数
class App extends React.Component {
  state = {
    count: 0
  }
  handleClick = () => {
    this.setState(() => {
      return {
        count: Math.floor(Math.random() * 3)
      }
    })
  }
  //因为两次生成的随机数可能相同,所以,此时不需要重新渲染
  // shouldComponentUpdate(nextProps, nextState) {
  //   console.log('最新状态:', nextState, '当前状态:', this.state);
  //   if (nextState.count === this.state.count) {
  //     return false
  //   }
  //   return true
  // }
  render() {
    // console.log('render');
    return (
      <div>
        <NumberBox count={this.state.count} />
        <button onClick={this.handleClick}>重新生成</button>
      </div>
    )
  }
}
class NumberBox extends React.Component {

  shouldComponentUpdate(nextProps) {
    console.log('最新的状态', nextProps, '当前状态', this.props);
    if (nextProps.count === this.props.count) {
      return false
    }
    return true
  }
  render() {
    console.log('render');
    return <h1>随机数:{this.props.count}</h1>
  }
}
const container = document.getElementById('root')
const root = createRoot(container)
root.render(<App />)
复制代码

纯组件

PureComponent与React.Component功能相似
区别:PureComponent内部自动实现了shouldComponentUpdate钩子,不需要手动比较
原理:纯组件内部通过分别对比前后两次props和state的值,来决定是否重新渲染组件。
复制代码
//随机数
class App extends React.PureComponent {
  state = {
    count: 0
  }
  handleClick = () => {
    this.setState(() => {
      return {
        count: Math.floor(Math.random() * 3)
      }
    })
  }
  render() {
    console.log('render');
    return (
      <div>
        <h1>随机数:{this.state.count}</h1>
        <button onClick={this.handleClick}>重新生成</button>
      </div>
    )
  }
}
const container = document.getElementById('root')
const root = createRoot(container)
root.render(<App />)
复制代码
经代码验证,随机数案例的两种情况在PureComponent下可以完成自动阻止渲染
 

纯组件内部对比

shallow compare(浅层对比)
对于值类型来说,比较两个值是否相同(直接赋值)
对于引用类型来说,只比较对象的引用(地址)是否相同
 注意:state或props中属性值为引用类型时,应该创建新数据,不要直接修改原数据
复制代码
//随机数
class App extends React.PureComponent {
  state = {
    obj: { count: 0 }
  }
  handleClick = () => {
    const newobj = { ...this.state.obj, count: Math.floor(Math.random() * 3) }
    this.setState(() => {
      return {
        obj: newobj
      } 
    })
  }
  render() {
    console.log('render');
    return (
      <div>
        <h1>随机数:{this.state.obj.count}</h1>
        <button onClick={this.handleClick}>重新生成</button>
      </div>
    )
  }
}
const container = document.getElementById('root')
const root = createRoot(container)
root.render(<App />)
复制代码

虚拟DOM和Diff算法

React更新视图的思想时:只要state变化就重新渲染视图
特点:思路非常清晰
完成部分更新,而不是更新整体
虚拟DOM:本质上是一个JS对象,用来描述你希望在屏幕上看到的内容(UI)
执行过程:
  1. 初次渲染时,React会根据数据初始state(Model),创建一个虚拟DOM对象(树)
  2. 根据虚拟DOM生成真正的DOM,渲染到页面中
  3. 当数据变化后(setState()),重新根据新的数据,创建新的虚拟DO吗对象(树)
  4. 与上一次得到的虚拟DOM对象,使用Diff算法对比,得到需要更新的内容
  5. 最终,React只将变化的内容更新到DOM中,重新渲染到页面。
复制代码
class App extends React.Component {
  state = {
    count: 0
  }
  handleClick = () => {
    this.setState(() => {
      return {
        count: Math.floor(Math.random() * 2)
      }


    })
  }
  render() {
    const el = (
      <div>
        <h1>随机数:</h1>
        <p>{this.state.count}</p>
        <button onClick={this.handleClick}>重新生成</button>
      </div>
    )
    console.log(el);
    return el
  }
}
const container = document.getElementById('root')
const root = createRoot(container)
root.render(<App />)
复制代码

 

posted @   终究还是避免不了遗憾  阅读(78)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示