React + 项目(从基础到实战) -- 第三期

news/2024/7/15 17:39:51 标签: react.js, javascript, ecmascript

react内置hooks

useState

如何让页面动起来(实时更新)

import React,{FC,useState} from "react";

  

const Demo:FC=()=>{

   let count=0; //普通js变量无法触发组件更新

  

  

   function add(){

    count++;

   
    console.log("count: ",count);

   }

    return <div>

        <button onClick={add}>add {count}</button>

    </div>

}

  
  

export default Demo;

在这里插入图片描述

为什么采用

state的改变可以触发函数组件的更新
(如果js变量不在jsx中使用,别用useState)

import React,{FC,useState} from "react";

  

const Demo:FC=()=>{

//    let count=0; //普通js变量无法触发组件更新

   const[count,setCount]=useState(0); //useState 可以触发组件更新

  

   function add(){

    // count++;

    setCount(count+1)

    console.log("count: ",count);

   }

    return <div>

        <button onClick={add}>add {count}</button>

    </div>

}

  
  

export default Demo;

在这里插入图片描述

特点

  1. 不可变数据
    不修改原数据,而是传入新的值

  2. 异步更新|
    函数中无法直接获取最新的值
    在这里插入图片描述

  3. 可能被合并
    使用函数state可以解决这个问题

在这里插入图片描述

 setCount(()=>{

        return count+5

    })

immer

是一个插件
解决state不可变数据的影响
安装 npm install -D immer

 import {FC,useState} from "react";

import {produce} from "immer";

  

const Demo : FC =()=>{

  

    const [list,setList]=useState(['x','y'])

    function add(){

        // setList(list.concat('z'));

        setList(

            produce(draft=>{

                draft.push('z')//直接在原数组上修改

            })

        )

  

    }

  

    return (

        <div>

        <h2>state 不可变数据</h2>

        <div>{JSON.stringify(list)}</div>

        <button onClick={add}>add  item</button>

  
  

        </div>

    )

}

  

export default  Demo;

useEffect

为什么

组件是一个函数,返回的是JSX片段,
组件初次渲染完成,即函数执行完成,
一般情况下函数执行完成就结束了
但是在state更新时,会触发组件更新,函数组件再次执行

为了解决以上问题,使用useEffect

import {FC,useEffect,useState} from "react"

const Demo:FC=()=>{

    useEffect(()=>{

        console.log("组件初次渲染完成");

  

        return ()=>{

            console.log("组件销毁时执行");

        }

    },[])//无依赖项,只执行一次

  

    const[count,setCount]=useState(0); //useState 可以触发组件更新

  

   function add(){

    // count++;

    setCount(()=>{

        return count+5

    })

    console.log("count: ",count);

   }

    return <div>

        <button onClick={add}>add {count}</button>

    </div>

  

}

  
  

export default Demo;

注意

发现useEffect 执行两次

在react 18 中,useEffect 在开发环境中执行两次,在生产环境中执行一次
(模拟组件生命周期,以便尽早暴露问题)
开发环境 npm run build 生存环境

useRef

  1. 操作DOM
  2. 可传入普通js变量,但是更新不会触发rerender

与vue3 ref 不同

  

import { FC,useRef } from "react";

  

const Demo:FC = () => {

     // 定义一个ref

    const inputRef = useRef<HTMLInputElement>(null) //dom节点

    const nameRef=useRef("pink") //不是dom节点,是一个普通的js变量

    function selectInput(){

        const input = inputRef.current;

        if(input){

            input.select(); // 选中输入框中的内容(Dom节点操作API)

        }

    }

  

    function changeName(){

        nameRef.current="blue"//修改ref的值,不引起rerender(state修改会触发组件更新)

        console.log(nameRef.current);

    }

    return (

        <>

        <input ref={inputRef} defaultValue={"hello world"}/>

        <button onClick={selectInput}>选中 input</button>

  

        <p>{nameRef.current}</p>

        <button onClick={changeName}>修改名字</button>

  

        </>

    )

}

  
  

export default Demo;

在这里插入图片描述

useMemo

缓存数据
不用每次执行函数组件(比如说 state修改)都重新生成 , 实现性能优化

import {FC,useMemo,useState} from "react"

  

const Demo : FC =()=>{

    const[num1,setNum1]=useState(0)

    const[num2,setNum2]=useState(0)

    const[text,setText]=useState("hello") //更新导致组件rerender

  
  

    const sum =useMemo(()=>{

        console.log("计算两数之和");//缓存

        return num1+num2;

    },[num1,num2])

  

    return (

        <>

        <p>sum = {sum}</p>

        <button onClick={()=>{setNum1(num1+1)}}>num1 : {num1}</button>

        <button onClick={()=>{setNum2(num2+1)}}>num2 : {num2}</button>

        <button onClick={()=>{setText(text+"1")}}>text : {text}</button>

        </>

    )

}

  
  
  

export default Demo;

在这里插入图片描述

useCallback

缓存函数

import {FC,useCallback,useState} from "react"

  
  

const Demo : FC =()=>{

    const [text,setText] = useState("hello")

    const fn1=()=>{

        console.log("fn1 text",text);

    }

  

    const fn2=useCallback(()=>{

        console.log("fn2 text",text);

    },[text])

  

    return(

        <>

        <button onClick={fn1}>fn1</button>

        <button onClick={fn2}>fn2</button>

        <div>

            <input value={text} onChange={e=>setText(e.target.value)}></input>

        </div>

        </>

    )

}

  
  
  

export default Demo;

自定义hooks

抽离公共部分,复用代码

同步案例

监听鼠标位置

  1. 自定义hook
import { useState,useEffect } from "react";

  

//获取鼠标位置

function useMouse(){

    const [x,setX]=useState(0);

    const [y,setY]=useState(0);

    const mouseMoveHandler=(e:MouseEvent)=>{

        setX(e.clientX);

        setY(e.clientY);

    }

  
  

    useEffect(()=>{

    //监听鼠标事件

        window.addEventListener('mousemove',mouseMoveHandler);

    //组件销毁时,一定要解绑DOM事件!!(可能会导致内存泄漏问题)

    return ()=>{

        window.removeEventListener('mousemove',mouseMoveHandler);

    }

    },[])

  
  

    return {x,y}

  

}

  
  

export default useMouse;
  1. app.tsx 中引入
//导入自定义hook


import useMouse from "./hooks/useMouse.ts";

function App() {


  const {x, y} = useMouse();

  return(

    <>

    <p>

      App Page

    </p>

    <div>x: {x}</div>

    <div>y: {y}</div>
    </>

  )

  

}

  

export default App

异步案例

模拟加载效果

import { useState,useEffect } from "react";

//异步获取消息

function getInfo():Promise<string>{

    return new Promise(resolve=>{

        setTimeout(()=>{

          resolve(Date.now().toString())  

        },1500)

    })

}

  
  

//自定义钩子

const useGetInfo=()=>{

    const[loading,setLoading]=useState(true)

    const[info,setInfo]=useState("")

  

    useEffect(()=>{

        getInfo().then(info=>{

            setLoading(false)

            setInfo(info)

        })

    },[])

    return {loading,info}

}

  
  

export default useGetInfo;

第三方hooks

提高开发效率

ahooks

react-hooks

hooks使用规则

  1. useXxx命名
  2. 组件内 获 其他hook 中可以调用
  3. 保证每次调用顺序一致(不能处于 if/for 内部)

面试题(闭包陷阱)

无法获取最新值

import {FC,useState} from 'react'

  

const Demo:FC =()=>{

    const[count,setCount]=useState(0)

    function add(){

        setCount(count+1)

    }

  

    function alertFn(){

      setTimeout(()=>{

        alert(count);

      },3000)

    }

  

    return(

        <>

        <p>闭包陷阱</p>

  

        <div>

        <span>{count}</span>

        <button onClick={add}>add</button>

        <button onClick={alertFn}>alert</button>

  

        </div>

        </>

    )

}

  
  

export default Demo;

使用ref解决在这里插入图片描述

import {FC,useState,useRef, useEffect} from 'react'

  

const Demo:FC =()=>{

    const[count,setCount]=useState(0)

    const countRef = useRef(0)

  

    function add(){

        setCount(count+1)

    }

  

    useEffect(()=>{

        countRef.current=count

    },[count])

  

    function alertFn(){

      setTimeout(()=>{

        // alert(count); //count 值类型

        alert(countRef.current); // ref 引用类型

      },3000)

    }

  

    return(

        <>

        <p>闭包陷阱</p>

  

        <div>

        <span>{count}</span>

        <button onClick={add}>add</button>

        <button onClick={alertFn}>alert</button>

  

        </div>

        </>

    )

}

  
  

export default Demo;

在这里插入图片描述


http://www.niftyadmin.cn/n/5468822.html

相关文章

Linux TUN设备实现Tunnel性能分析

一、TUN/TAP设备原理&#xff1a; Linux的TUN/TAP设备是一种可以使得应用层与TCP/IP协议栈交互的驱动模块&#xff0c;通常用于组建虚拟局域网中的点对点隧道&#xff08;Tunnel&#xff09;&#xff0c;可以工作于2层&#xff08;TAP设备&#xff09;和3层&#xff08;TUN设备…

Python学习之-迭代器和生成器

前言&#xff1a; 在Python中&#xff0c;迭代器&#xff08;Iterator&#xff09;和生成器&#xff08;Generator&#xff09;是实现迭代协议的对象&#xff0c;用于遍历集合中的元素。它们之间有联系&#xff0c;但也有一些关键的差异。 1 迭代器&#xff08;Iterator&…

SpringCloud Hystrix 服务熔断、服务降级防止服务雪崩

文章目录 SpringCloud Hystrix 熔断器、服务降级防止服务雪崩需求背景引入依赖启动类加Hystrix注解接口配置熔断常规配置超时断开错误率熔断请求数熔断限流 可配置项HystrixCommand.Setter参数Command Properties 服务降级 SpringCloud Hystrix 熔断器、服务降级防止服务雪崩 H…

ES6展开运算符

1.展开可迭代对象&#xff08;简单理解为数组和伪数组&#xff09;&#xff0c;如数组、 NodeList 、arguments。 可以通过展开运算符把一个伪数组转换为数组 const a [...document.body.children]; console.log(a); console.log(Array.isArray(a));2.实现数组的浅拷贝 cons…

VMware创建Ubuntu虚拟机详细教程

下载ISO映像文件 进入官网下载&#xff1a;Download Ubuntu Desktop | Download | Ubuntu 下面是一些其他的下载路径&#xff1a; 中国官网 https://cn.ubuntu.com/ 中科大源 Index of /ubuntu-releases/ (ustc.edu.cn) 阿里云开源镜像站 ubuntu-releases安装包下载_开源镜像…

天眼护航 安全无界:天通哨兵PS02—电力巡检保护的智能利器

在电力行业中&#xff0c;输电线路的安全稳定运行对于保障社会经济活动至关重要。然而&#xff0c;广阔的输电线路常常穿越复杂的地形和恶劣的自然环境&#xff0c;给电力巡检和保护工作带来了巨大挑战。 为了提高巡检效率和响应速度&#xff0c;更好地保障电力设施的安全运行…

设计模式|状态机模式(State Machine Pattern)

文章目录 结构使用步骤示例使用状态机的场景常见面试题 状态机模式&#xff08;State Machine Pattern&#xff09;是一种用于描述对象的行为软件设计模式&#xff0c;属于行为型设计模式。在状态机模式中&#xff0c;对象的行为取决于其内部状态&#xff0c;并且在不同的状态下…

Express框架搭建项目 node.js

文章目录 引言Express框架介绍express安装环境准备写一个简单的项目展示 文章总结 引言 Express是一个基于Node.js平台的轻量级Web应用框架&#xff0c;它提供了简洁的API和丰富的功能&#xff0c;使得开发者能够快速地构建Web服务器和API。本文将带领大家从零开始&#xff0c…