react中关于类式组件和函数组件对props、state、ref的使用

发布于:2024-04-18 ⋅ 阅读:(31) ⋅ 点赞:(0)

文章中有很多蓝色字体为扩展链接,可以补充查看。

常用命令使用规则

组件编写方式:

1.函数式

function MyButton() {
//直接return 标签体
  return (
   <>……</>
  );
}

2.类

class MyButton extends React.Component {
//在render方法中,return 标签体
  render() {
    return <>……</>
  }
}

虚拟dom到底是怎么个事?

-虚拟dom:它本质上是一个拥有着对应着真实的DOM元素的属性集合的 JavaScript对象。
为什么要使用虚拟dom?

答案:我们通过对dom的操作实现浏览器更新,当应用的项目比较小的时候这么做是没有问题的,但是当变更频繁或者需要操作的dom数量大的时候就非常不合适了。因为dom的变更会引起浏览器的重排和重绘,这是十分消耗性能的。
因此引入虚拟dom的概念来改善这种问题,在渲染dom之前,存储一份虚拟dom。每次去变更dom,都会使用最新的虚拟dom去对比之前的,只更新增加不同的部分,避免全量更改真实dom减少开销,以下是使用虚拟dom的好处。

  1. 性能优化: 虚拟DOM使得React可以将多次DOM操作合并为一次,从而减少了实际的DOM操作次数,提高了性能。
  2. 快速更新: React通过比较虚拟DOM和实际DOM的差异,只更新必要的部分,避免了不必要的重新渲染,提高了页面的响应速度。
  3. 框架内部使用: 虚拟DOM是React框架内部使用的一种机制,开发者通常无需直接操作虚拟DOM,React会在合适的时机将其转化为真实的DOM。
vue与react的diff算法的区别

React 和 Vue 都采用了高效的虚拟 DOM Diff 算法来优化视图更新,尽管它们在具体实现上有所不同,但核心目标都是尽可能地减少对真实 DOM 的操作以提升性能。以下是 React 和 Vue diff 算法的主要对比点:

  1. Diff 策略

    • React:React 使用了深度优先搜索(DFS)进行树形结构的比较,并且在同层节点中,默认采用“逐个”比较的方式,只有在找到 key 相同的节点时才进行移动操作,而不是重新创建。当遇到列表类型的子节点时,若没有提供稳定的 key,则会默认复用首尾的节点,中间的节点会被全部卸载并重新创建。
    • Vue:Vue 也是基于 DFS 进行树形结构比较,但它采用的是“双向”遍历的方式,在确定待插入、移动或删除的元素时效率更高。Vue 也强调使用 key 来提高列表渲染性能,如果提供了 key,Vue 可以更精确地识别出被移动或复用的元素。
  2. 异同处理

    • React:React 在同一层级的节点比较中,只要类型不同就会直接替换整个子树,这可能导致不必要的DOM操作。
    • Vue:Vue 对于组件的修改更为灵活,它会尝试复用现有组件实例,即使其类型发生了变化。但如果数据或者 prop 有显著差异,也会触发重建。
  3. 调度策略

    • React:React 16 引入了 Fiber 架构,实现了可中断和恢复的 Diff 算法,允许浏览器在渲染过程中进行其他任务,提高了 UI 响应速度。
    • Vue:Vue 的异步更新队列机制,使得多个数据更改在一起时可以统一进行一次视图更新,一定程度上减少了计算量。
  4. 优化手段

    • React:通过 shouldComponentUpdate 或者 PureComponent、React.memo 提供组件级别的优化。
    • Vue:Vue 则是默认跟踪依赖,通过对象属性代理和响应式系统自动检测变更,配合 computed 属性和 watch 选项进行优化。

总结来说,React 和 Vue 在 Diff 算法上的差异主要体现在具体的遍历策略、组件更新逻辑以及优化方式上,两者都在努力减少不必要的 DOM 操作,提升页面渲染性能。实际开发中,合理使用 key、遵循最佳实践都可以进一步提升二者在大规模数据更新场景下的表现。

使用 JSX 书写标签语言_规则

  1. 标签闭合
  2. 只能返回一个根元素
  3. 使用驼峰式命名法给所有 大部分属性命名!
css
//常用举例 css
<img className="avatar" />

//{}中写入变量
<img
  className="avatar"
  style={{
    width: user.imageSize,
    height: user.imageSize
  }}
/>

//如果你有多个条件类
<img className={cn('row', {
      selected: isSelected,
      large: size === 'large',
      isActived && 'isActived '
    })} />

props、state、ref

props

简单来说props就是组件对外的接口,用于接收父级组件的传递过来的参数的一个口子。通过这个口子可以使子组件使用父组件传递过来的内容。

绝不能修改自身的 props。

- 函数式组件 -
function Button({ onSmash, children }) {
  return (
    <button onClick={onSmash}>
      {children}
    </button>
  );
}

export default function App() {
  return (
    <div>
      <Button onSmash={() => alert('正在播放!')}>
        播放电影
      </Button>
    </div>
  );
}
//总结:在标签中传递,方法参数接收
- 类式组件
import React ,{Component} from 'react'
class App extends Component {
    constructor(props){
      super(props)
    }
    render(){
     return (
    <div>
      <Button onSmash={() => alert('正在播放!')}>
        播放电影
      </Button>
    </div>
  );
  }
}
//总结:在标签中传递,在cunstrctor中接收

在React的类式组件中,即使不写constructor构造函数,也依然可以使用props。React会自动为类组件实例初始化props,无需在构造函数中手动传递。你可以直接在组件类的其他生命周期方法或者成员函数中通过this.props访问到传入的props。

import React ,{Component} from 'react'
class MyComponent extends Component{
   render(){
      const {name ,age } = this.props;
      return (<div>我叫{name},我已经{age}岁了!</div>)
   }
}
//使用组件时使用标签传递props
<MyComponent name='喵喵' age={3} />

state

它是React组件内的一个对象,用于存储组件的动态数据或状态。每个React组件都有自身的state,并且它可以随时间发生变化,进而驱动组件重新渲染,以反映新的状态所导致的UI变化。

  • state如同一张快照,这个观点很重要,请跳转查看。
  • 当你想要批量的操作state值的时候可以使用箭头函数处理
  • 如果一个值可以基于现有的 props 或 state 计算得出,不要把它作为一个 state,而是在渲染期间直接计算这个值。
function Form() {
  const [firstName, setFirstName] = useState('Taylor');
  const [lastName, setLastName] = useState('Swift');
  // ✅ 非常好:在渲染期间进行计算
  const fullName = firstName + ' ' + lastName;
  // ...
}
  • 更新state的对象是全覆盖模式,而不是替换模式。
  • 操作数组
    在这里插入图片描述
- 函数式组件 -
//1.导入useState hook
import { useState } from 'react';

export default function Gallery() {
  //2.声明state变量 name
  const [name, setName] = useState('喵喵');
  function handleChangeName() {
  //3.改变state变量
    setName('朵喵喵');
  }
  return (
    <>
      <button onClick={handleChangeName}>换个名字</button>
      {name}
    </>
  );
}
- 类式组件 -
import React, { Component } from 'react';

class YourComponent extends Component {
 //1.在constructor中声明
 //constructor(props) {
 //  super(props);
 //  this.state = {
 //    name: "喵喵"
 //  };
 //}
  
  //2.直接声明
  state = {
     name: "喵喵"
  };
 
  handleButtonClick = () => {
     this.setState({
        name: '朵喵喵',
     });
  }

  render() {
   return ( <button onClick={this.handleButtonClick}>{this.state.name}</button> );
  }
}

export default YourComponent;

ref

当你希望组件“记住”某些信息,但又不想让这些信息 触发新的渲染 时,你可以使用 ref 。state的改变会导致页面重新被渲染,而使用ref定义的变量是不会被渲染的。就相当于重新开辟了一个空间用于存储不需要被渲染到页面上的数据,减少一些不必要的渲染开支。

如何使用?
//引入 hook
import { useRef } form 'react'

// 定义,useRef返回一个对象,相当于 const name = useRef('喵喵'){ return { current:‘喵喵’ } }
// 到组件挂载后,this.myDivRef.current才指向真实DOM节点
const name = useRef('喵喵')       //  = { current :'喵喵'}

//使用
export default function Cat(){
   return (<div onClick="() => name.current = '朵喵喵'">改名</div>)
}
ref与state的区别

==更加建议使用state ==
在这里插入图片描述

扩展应用,操作dom

由于 React 会自动处理更新 DOM 以匹配你的渲染输出,因此你在组件中通常不需要操作 DOM。但是,有时你可能需要访问由 React管理的 DOM 元素。

直接操作DOM并不是通常推荐的做法

函数式
//1.
import React, { useRef, useEffect } from 'react';

function MyComponent() {
  //2.
  const divRef = useRef(null);
  function handleChange (){
    //4.修改
    divRef.current.style.backgroundColor = 'red'
  }
  return (
    //3.使用定义的变量
    <div ref={divRef} onClick={handleChange}>
      这个div的背景将会被设置为红色
    </div>
  );
}

export default MyComponent;
类式

在 React 中,JSX 的渲染必须是纯粹操作,不应该包含任何像修改 DOM 的副作用。

import React, { Component, createRef } from 'react';

class MyComponent extends Component {
  myDivRef = createRef();
  
  componentDidMount() {
    // 到组件挂载后,this.myDivRef.current才指向真实DOM节点
    if (this.myDivRef.current) {
      this.myDivRef.current.style.backgroundColor = 'red';
    }
  }

  render() {
    return (
      <div ref={this.myDivRef}>
        这个div的背景将会被设置为红色
      </div>
    );
  }
}

export default MyClassComponent;

关于生命周期