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 的规则。

相关推荐
步行cgn22 分钟前
Vue 中的数据代理机制
前端·javascript·vue.js
GH小杨26 分钟前
JS之Dom模型和Bom模型
前端·javascript·html
星月心城1 小时前
JS深入之从原型到原型链
前端·javascript
MessiGo1 小时前
Javascript 编程基础(5)面向对象 | 5.2、原型系统
开发语言·javascript·原型模式
你的人类朋友2 小时前
🤔Token 存储方案有哪些
前端·javascript·后端
烛阴2 小时前
从零开始:使用Node.js和Cheerio进行轻量级网页数据提取
前端·javascript·后端
liuyang___2 小时前
日期的数据格式转换
前端·后端·学习·node.js·node
西哥写代码2 小时前
基于cornerstone3D的dicom影像浏览器 第三十一章 从PACS服务加载图像
javascript·pacs·dicom
贩卖纯净水.3 小时前
webpack其余配置
前端·webpack·node.js