React(7)

1.React Hooks

使用hooks理由

  1. 高阶组件为了复用,导致代码层级复杂

  2. 生命周期的复杂

  3. 写成functional组件,无状态组件 ,因为需要状态,又改成了class,成本高

1.1 useState

useState();括号里面处的是初始值;返回的是一个数组【值,改变值的唯一方法】

因此可以通过解构:例如

const [name,setName] =useState("www")

javascript 复制代码
import React, { useState } from 'react'

export default function APP() {
        const [name,setName] =useState("www")

        return (
            <div>
                {name}
                <button onClick={()=>{
                    setName("xxx");
                }}>click</button>
            </div>
        )
    
}

只要使用setXX后,函数式组件都会重新执行一次。类似setState()

重新执行时,会保存name的状态。不会被重新赋值

比如:

count从0 开始 点击一次+1 再点击就是2,3,4,5,。。。

而不是一直是0,因为useState是一个记忆函数,会记住状态。

而代码中的mycount会一直是0。

1.2 useEffect和useLayoutEffect

useEffect(处理副作用)和useLayoutEffect (同步执行副作用)

Function Component 不存在生命周期,所以不要把 Class Component 的生命周期概念搬过来试图对号入座。

比如发请求那数据,如果直接如下所写

axios发送请求获取数据成功后,调用setlist(),然后就会重新执行一次组件,导致又调用anxios请求,然后又setlist() 一直重复下去。

因此我们需要用到:useEffect() 第2个参数传空数组就只会执行一次

javascript 复制代码
import axios from 'axios'
import React, { Component, useEffect, useState } from 'react'


export default function APP() {
 
    const [list,setList] = useState([])

    useEffect(()=>{
        axios.get("film.json").then(res=>{
            console.log(res);
            setList(res.data)
        })
    },[])   //传空数组    [依赖的状态;空数组表示不依赖]

    
    
    return (
        <div>
          {list.map(item=>
            <li key={item.filmId}>{item.name}</li>)}
        </div>
    )

}

如果第2个参数传的不是空数组,而是有依赖,当依赖被改变就会执行

不要对 Dependencies 撒谎, 如果你明明使用了某个变量,却没有申明在依赖中,你等于向 React 撒了谎,后果 就是,当依赖的变量改变时,useEffect 也不会再次执行, eslint会报警告。

例如:将名字首字母改为大写

javascript 复制代码
import React, { Component, useEffect, useState } from 'react'


export default function APP() {
 
    const [name,setName] = useState('wuweiwei')

    useEffect(()=>{
        setName(name.substring(0,1).toUpperCase()+name.substring(1))
    },[])
    
    return (
        <div>
          app==========={name}
          <button onClick={()=>{
            setName("xiaoming")
          }}>click</button>
        </div>
    )

}

可以发现当点击按钮,名字改变后并没有对名字进行首字母大写的修改。因为传的是空数组,没有传入name依赖。即只要name值被改变,useEffect第一个参数回调函数就会被执行。如果是相同的值,就不会执行。

useEffect(()=>{

setName(name.substring(0,1).toUpperCase()+name.substring(1))

},[name])

销毁时的回调函数

javascript 复制代码
useEffect(() => {
   
    return () => {
        //组件被销毁时才会执行此回调函数
    };
 }, [依赖的状态;空数组,表示不依赖])

注意:

1.useEffect可以写多个;

useEffect和useLayoutEffect有什么区别?

简单来说就是调用时机不同, useLayoutEffect 和原来 componentDidMount & componentDidUpdate 一致,在 react完成DOM更新后马上同步调用的代码,会阻塞页面渲染。而 useEffect 是会在整个页面渲染完才会调用的 代码。 官方建议优先使用 useEffect。

在实际使用时如果想避免页面抖动(在 useEffect 里修改DOM很有可能出现)的话,可以把需要操作DOM的代码 放在 useLayoutEffect 里。在这里做点dom操作,这些dom修改会和 react 做出的更改一起被一次性渲染到屏幕 上,只有一次回流、重绘的代价

1.3 useCallback

防止因为组件重新渲染,导致方法被重新创建 ,起到缓存作用,可提高性能; 只有第二个参数 变化了,才重新声明一次。

javascript 复制代码
var handleClick = useCallback(()=>{
    console.log(name)
  },[name])

<button onClick={()=>handleClick()}>hello</button>


 //只有name改变后, 这个函数才会重新声明一次,
 //如果传入空数组, 那么就是第一次创建后就被缓存, 如果name后期改变了,拿到的还是老的name。
 //如果不传第二个参数,每次都会重新声明一次,拿到的就是最新的name.
    

1.4 useMemo 记忆组件

useCallback 的功能完全可以由 useMemo 所取代,如果你想通过使用 useMemo 返回一个记忆函数也是完全可以的。

javascript 复制代码
useCallback(fn, inputs) is equivalent to useMemo(() => fn, inputs).

唯一的区别是:useCallback 不会执行第一个参数函数,而是将它返回给你,而 useMemo 会执行第一个函数并 且将函数执行结果返回给你。所以在前面的例子中,可以返回 handleClick 来达到存储函数的目的。

所以 useCallback 常用记忆事件函数,生成记忆后的事件函数并传递给子组件使用。而 useMemo 更适合经过函数 计算得到一个确定的值,比如记忆组件。

1.5 useRef

和React.createRef使用相同,放在dom上得到的是dom对象,放在组件上得到的是组件对象。

javascript 复制代码
var mytext=useRef(0); //也带有记忆功能

<input ref={mytext}/>

mytext.current

1.6 useContext(减少组件层级)

javascript 复制代码
import React from 'react'
var GlobalContext = React.createContext()
// 注意此时的reduecer 返回值是一个对象 {isShow:false,list:[]}
function App(props) {
    let [state, dispatch] = useReducer(reducer, { isShow: true, list: [] })
    return <GlobalContext.Provider value={{
        dispatch
    }}>
        <div>
            {
                state.isShow ?
                    <div >我是选项卡</div>
                    : null
            }
            {props.children}
        </div>
    </GlobalContext.Provider>
}
function Detail() {
    var { dispatch } = useContext(GlobalContext)
    useEffect(() => {
        //隐藏
        dispatch({
            type: "Hide",
            payload: false
        })
        return () => {
            //显示
            dispatch({
                type: "Show",
                payload: true
            })
        };
    }, [])
    return <div>
        detail
    </div>
}

1.7 useReducer

主要是将状态从组件中分离

javascript 复制代码
import React, { Component } from 'react'
import { useReducer } from 'react'

//处理函数
const reducer=(prevState,action)=>{
    console.log("进来了",prevState,action);  //prevState是状态对象  action是dispatch中的对象
    let newState={...prevState}
    switch(action.type){
        case "-":
            newState.count--
            return newState
        case "+":
            newState.count++
            return newState
        default:
            return prevState
    }

}

//外部的对象
const initialState={
    count:0,
}

export default function App(){
    const [state,dispatch]=useReducer(reducer,initialState)  //参数1  处理函数   参数2:初始的state

    return (
        <div>
            <button onClick={()=>{
                dispatch({
                    type:"-"
                })
            }}>-</button>
            {state.count}
            <button onClick={()=>{
                dispatch({
                    type:"+"
                })
            }}>+</button>
        </div>
    )
}

过程:使用const [a,b]=useReducer(参数1,参数2) //参数1 处理函数 参数2:初始的state

通过a,b变量保存

然后组件内使用了b,就会自动调用参数1的处理函数const reducer=(prevState,action)=>

//prevState是状态对象 action是dispatch中的对象

这里面return回去的state会自动到状态中。

1.8 自定义hooks

当我们想在两个函数之间共享逻辑时,我们会把它提取到第三个函数中。

必须以"use"开头吗?必须如此。这个约定非常重要。不遵循的话,由于无法判断某个函数是否包含对其内部 Hook 的调用,React 将无法自动检查你的 Hook 是否违反了 Hook 的规则。

相关推荐
m0_748256562 分钟前
Windows 11 Web 项目常见问题解决方案
前端·windows
LOVE️YOU3 分钟前
HTML&CSS&JavaScript&DOM 之间的关系?
前端·javascript·css·html
胡西风_foxww4 分钟前
【es6复习笔记】集合Set(13)
前端·笔记·es6·set·集合
m0_7482449613 分钟前
VUE前端实现天爱滑块验证码--详细教程
前端·javascript·vue.js
叫我菜菜就好1 小时前
【Flutter_Web】Flutter编译Web第三篇(网络请求篇):dio如何改造方法,变成web之后数据如何处理
前端·网络·flutter
NoneCoder1 小时前
CSS系列(26)-- 动画性能优化详解
前端·css·性能优化
滚雪球~1 小时前
@vue/cli启动异常:ENOENT: no such file or directory, scandir
前端·javascript·vue.js
GDAL1 小时前
vue3入门教程:ref函数
前端·vue.js·elementui
GISer_Jing1 小时前
Vue3状态管理——Pinia
前端·javascript·vue.js
好开心331 小时前
axios的使用
开发语言·前端·javascript·前端框架·html