react(第三天)

本文详细解析了PureComponent在React中如何通过浅比较优化组件更新,重点讲解了对象比较的策略,并对比了与Component的差异,包括ref的使用和自定义Hooks的应用实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

PureComponent

PureComponent 提供了一个具有浅比较的 shouldComponentUpdate 方法,其他和 Component 完全一致

浅比较:新修改的数据与原本的数据如果一样则不予更新,否则更新

1) 字符串正常
2) 对象的话,存的是地址,比较的也是地址,按照地址再去找具体的值,所以没更换新地址的话,那么原本去赋值就不太行,
需要解构赋值,this.setState({list:[…list]})

Component 不管与原数据是否一样都重新全部更新
–App.js

import React, {PureComponent, Component } from 'react';
// Component  不管与原数据是否一样都重新全部更新
// PureComponent 提供了一个具有浅比较的 shouldComponentUpdate 方法,// 其他和 Component 完全一致// 浅比较:新修改的数据与原本的数据如果一样则不予更新,否则更新//        1) 字符串正常//        2) 对象的话,存的是地址,比较的也是地址,按照地址再去找具体的值,//                  所以没更换新地址的话,那么原本去赋值就不太行,//                需要解构赋值,this.setState({list:[...list]})class App extends 

PureComponent {
  state = {
    name:"尖叫",
    list:["运动饮料-01","运动饮料-02","运动饮料-03"]
  }
  render(){

    let {name,list} = this.state;
    return(
      <div>
        <h1>{name}</h1>
        <ul>
            {
              list.map((item,index)=>{
                return <li key={index}>{item}</li>
              })
            }
        </ul>
        <button onClick={()=>{
          this.setState({name:"红牛"})
        }}>升级</button>

        <button onClick={()=>{
          list.push("新口味");
          // 使用PureComponent时,注意使用解构赋值的方式!!!
          this.setState({list:[...list]})
          //this.setState({list}) //PureComponent下使用这个的话,扩大功能实现不了
        }}>扩大</button>
      </div>
    )
  }}
export default App;
–index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(
  // <React.StrictMode>
    <App />,
  // </React.StrictMode>,
  document.getElementById('root'));

component与PureComponent的区别
如果使用Component,则不管与原数据是否一样都会重新全部更新;
以下是使用 PureComponent 的情况:修改的数据与原本的若一样则不予更新

ref

旧版 - string ref
主流 - createRef()

*注意:在 组件挂载完成之后及更新之后使用

本次结合一个滚动小插件来使用ref:

new BScroll()()内填入要滚动的对象,比较适用于移动端,可以拖拽,不能滚轮滑动

1.旧版用法示例:

import React, {PureComponent, createRef } from 'react';
import BScroll from "better-scroll"

// 滚动小插件:// new BScroll(),()内填入要滚动的对象// 注意:只能在 组件挂载完成之后及更新之后使用!!!!!!
// 新的小写法 ~ ~ ~

let list = [...(".".repeat(100))];
console.log(list)
class App extends PureComponent {
    // 新版的一个小弊端:需要新的话需要再重新创建一个,再绑到一个新的
    // box = createRef();// 2.新版ref写法(主流方式)-----  需要先在类里创建一个空的,存在box当中
    // list = createRef();
    componentDidMount(){
        console.log(this); //新版的写法时,不在refs里了,多了一个box,box: {current: div}
        console.log(this.refs); //ref的集合,旧版含有集合,新版写法里没有 
        console.log(this.refs.box);
        // console.log(this.box.current);
        new BScroll(this.refs.box);//1.旧版 ***
        // new BScroll(this.box.current);//2.新版-----
    }
    render(){
      return(
        <div  style={{
                height:"300px",
                border:"1px solid #000",
                overflow:"hidden"
              }}
              ref="box"       // 1.旧版***  绑定  其他地方例如:挂载完成之后及更新之后的生命周期函数 可以获取到
              // ref = {this.box}   // 2.新版----- 绑到box上,box属性中存了一个ref
        >
            <ul style={{
                  margin:0,
                  padding:0,
                  listStyle:"none"
                }}
                ref="list"
                // ref = {this.list}  //输出this时,则会多出一个list属性   list: {current: ul}
            >
                  {
                    list.map((item,index)=>{
                      return <li key={index}>这是第{index+1}个li</li>
                    })
                  }
            </ul>
        </div>
      )
    }
    }
export default App;

children

组件标签对之间的内容会被当做一个特殊的属性 props.children 传入组件内容
可以自定义结构的组件的常用形式

children
传递函数
传递子组件
示例一:

dangerouslySetInnerHTML
直接设置标签的 innerHTML

import React, {PureComponent} from 'react';/*
  只能接后端返回回来的校检过的安全的数据
*/
let message = `
          <h1>夏天快乐</h1>
          <p>夏天都快过去了</p>
          `class App extends PureComponent {
  render(){
    return(
      <div dangerouslySetInnerHTML={{
          __html:message
      }}>
      </div>
    )
  }}
export default App;

key 的问题

在 React ,组件每次更新时,会生成一个 虚拟DOM,和原有的虚拟DOM进行对比。
如果是批量生成的一组元素,那React就会根据 key 值去做对比
一个列表中的每一项 key 是唯一的
如果列表中发生顺序等操作变化,key 一定要用数据的id

import React, {PureComponent} from 'react';
class App extends PureComponent {
  state={
    data:[
      {
        id:0,
        content:"第1条数据"
      },
      {
        id:1,
        content:"第2条数据"
      },
      {
        id:2,
        content:"第3条数据"
      },
      {
        id:3,
        content:"第4条数据"
      },
      {
        id:4,
        content:"第5条数据"
      }
    ]
  }
  render(){
    let {data} = this.state;
    return(
      <div>
        {
          data.map((item,index)=>{
            {/* 尽量不要用下标索引值index为key,有一个变则会整体都变,很耗性能。  
                用id则会一一进行对比,看是否发生了改变,没变则不动,改变的则进行变动。则只会改变选中的id对应的数据,不会整体都变
                DOM最耗性能,计算功能本来就是计算机擅长的
            */}
            // return <p key={index}>  
            return <p key={item.id}>  
                      {item.content}
                      <a onClick={()=>{
                        data = data.filter(itemData=>itemData!==item)
                        this.setState({
                          data:[...data]
                        })
                      }}>删除</a>
                    </p>
          })
        }
      </div>
    )
  }}
export default App;

自定义Hooks

react hooks 是 React 16.8 的新增特性。 它可以让我们在函数组件中使用 state 、生命周期以及其他 react特性,而不仅限于 class 组件。react hooks 的出现,标示着 react中不会在存在无状态组件了,只有类组件和函数组件。具体可查看官网。
优势:

  1. 函数组件不能使用state,遇到交互更改状态等复杂逻辑时不能更好地支持,hooks让函数组件更靠近class组件,拥抱函数式编程。
  2. 解决副作⽤问题,hooks出现可以处理数据获取、订阅、定时执行任务、手动修改 ReactDOM这些⾏为副作用,进行副作用逻辑。比如useEffect。
  3. 更好写出有状态的逻辑重用组件。
  4. 让复杂逻辑简单化,比如状态管理:useReducer、useContext。
  5. 函数式组件比class组件简洁,开发的体验更好,效率更⾼,性能更好。
  6. 更容易发现无用的状态和函数。

例子:

 
import React{useEffect} from 'react' 
//封装的Hooks⽤用use开头
const useChangeTitle= (title) =>{
	useEffect(()=>{ document.title=title
},[title]) }

exprot default (props)=>{ useChangeTitle("⾃自定义修改标题Hooks") return (
	<div> 测试⾃自定义Hooks
	</div> )
}
  1. 只在顶层调⽤Hooks Hooks的调⽤,尽量只在顶层作⽤域进行调用不要在循环,条件或者是嵌套函数中调⽤Hook,否则可能会⽆无 ,确保每次组件渲染时都以相同的顺序调⽤Hook。
  2. 只在函数组件调⽤Hooks,React Hooks目前只支持函数组件,所以⼤大家别在class组件或者普通的函数⾥面调⽤Hook钩⼦函数
  3. React Hooks的应用场景在函数组件,自定义hooks

在未来的版本React Hooks会扩展到class组件,但是现阶段不能再class⾥使⽤。

useEffect

使用 Effect Hook
Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。

如果熟悉 React class 的生命周期函数,你可以把 useEffect Hook 看做
componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个函数的组合。

无需清除的 effect
有时候,我们只想在 React 更新 DOM 之后运行一些额外的代码。比如发送网络请求,手动变更 DOM,记录日志,这些都是常见的无需清除的操作。因为我们在执行完这些操作之后,就可以忽略他们了。让我们对比一下使用 class 和 Hook 都是怎么实现这些副作用的。
使用 class 的示例
在 React 的 class 组件中,render 函数是不应该有任何副作用的。一般来说,在这里执行操作太早了,我们基本上都希望在 React 更新 DOM 之后才执行我们的操作。
这就是为什么在 React class 中,我们把副作用操作放到 componentDidMount 和 componentDidUpdate 函数中。回到示例中,这是一个 React 计数器的 class 组件。它在 React 对 DOM 进行操作之后,立即更新了 document 的 title 属性

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  componentDidMount() {
    document.title = `You clicked ${this.state.count} times`;
  }
  componentDidUpdate() {
    document.title = `You clicked ${this.state.count} times`;
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}

注意,在这个 class 中,我们需要在两个生命周期函数中编写重复的代码。

这是因为很多情况下,我们希望在组件加载和更新时执行同样的操作。从概念上说,我们希望它在每次渲染之后执行 —— 但 React 的 class 组件没有提供这样的方法。即使我们提取出一个方法,我们还是要在两个地方调用它。

现在让我们来看看如何使用 useEffect 执行相同的操作。

使用 Hook 的示例

import React, { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

useEffect 做了什么? 通过使用这个 Hook,你可以告诉 React 组件需要在渲染后执行某些操作。React 会保存你传递的函数(我们将它称之为 “effect”),并且在执行 DOM 更新之后调用它。在这个 effect 中,我们设置了 document 的 title 属性,不过我们也可以执行数据获取或调用其他命令式的 API。

为什么在组件内部调用 useEffect? 将 useEffect 放在组件内部让我们可以在 effect 中直接访问 count state 变量(或其他 props)。我们不需要特殊的 API 来读取它 —— 它已经保存在函数作用域中。Hook 使用了 JavaScript 的闭包机制,而不用在 JavaScript 已经提供了解决方案的情况下,还引入特定的 React API。

useEffect 会在每次渲染后都执行吗? 是的,默认情况下,它在第一次渲染之后和每次更新之后都会执行。(我们稍后会谈到如何控制它。)你可能会更容易接受 effect 发生在“渲染之后”这种概念,不用再去考虑“挂载”还是“更新”。React 保证了每次运行 effect 的同时,DOM 都已经更新完毕。

react-router

react-router 是对你前端路由的管理配置.

注意
React项目的可用的路由库是React-Router,当然这也是官方支持的。它也分为:

  • eact-router 核心组件
  • react-router-dom 应用于浏览器端的路由库(单独使用包含了react-router的核心部分)
  • react-router-native 应用于native端的路由

我用的web端路由库:

{
	"react-router-dom": "^5.1.2"
}

安装

npm install --save react-router-dom

Router

就是说Router只是一个所有router组件的公共接口,要使用则用它的实现类组件:

<BrowserRouter>
<HashRouter>
<MemoryRouter>
<NativeRouter>
<StaticRouter>

这些就是我现在了解的一些react知识

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值