【React】 第十三部分 Hooks

【React】 第十三部分 Hooks



13. Hooks

13.1 什么是Hooks?

Hook是React 16.8.0版本增加的新特性/新语法

可以让你在函数组件中使用 state ,ref 以及其他的 React 特性


13.2 State Hook

State Hook 作用 :让函数组件也可以有state状态, 并进行状态数据的读写操作

在这里说几个细节上的问题:

  1. 该函数组件执行次数为 n+1 次, 1 是初始化那一次

  2. 函数重新执行按理说初始化的值会一直被覆盖,导致数据不能发生变化

    问题 :为什么数据是可以发生变化的?

    原因:react底层做了处理,在初始化的时候将初始化的值存了起来,下次
    执行的时候使用的是存起来的值

  3. StateHook中修改状态的方法不会去合并对象而是去替换对象,这点和类组件中的setState()不同

import React, { Component } from 'react'

export default function Test (){
    /*
        调用React.useState(initValue) ,传入的是初始化的值
        该方法返回的是一个数组
            - 数组中第一个参数为:初始化的值/当前状态的值
            - 数组中第二个参数为:操作该状态的方法
     */
    const [count,setCount] = React.useState(0)
    const [person,setPerson] = React.useState([
        {
            name:'Jack',
            age:18,
            id:'001'
        }
    ])
    const [obj,setObj] = React.useState({name:'Jane',age:52})

    const add = () =>{
        // 第一种写法,参数为非函数值
        // 直接指定新的状态值, 内部用其覆盖原来的状态值
        setCount(count+1)
    }

    const subtract = () =>{
        // 第二种写法,参数为函数
        // 接收原本的状态值, 返回新的状态值, 内部用其覆盖原来的状态值
        setCount(count=>count-1)
    }

    const addPerson = () =>{
        setPerson((person)=>{
            let obj = {id:'002',name:'Mark',age:12}
            return [obj,...person]
        })
    }

    /*
        在这里需要注意:它和类组件的中的setState不同
        不会进行合并对象而是去替换对象 
     */
    const changeName = () =>{
        setObj((obj)=>{
            return Object.create(Object.assign(obj,{name:'Lili'}))
        })
    }

    return (
        <div>
            <h2>当前求和为:{count}</h2>
            <h2 onClick={changeName}>{obj.name} --- {obj.age}</h2>
            <button onClick={add}>点我+1</button>
            <button onClick={subtract}>点我-1</button>
            <button onClick={addPerson}>添加人员</button>
            {
                person.map((item)=>{
                    return <li key={item.id}>{item.name} --- {item.age}</li>
                })
            }
        </div>
    )
}


13.3 Effect Hook

Effect Hook 作用: 可以在函数组件中执行副作用操作(用于模拟类组件中的生命周期钩子)

React中的副作用操作:

1. 发ajax请求数据获取
2. 设置订阅 / 启动定时器
3. 手动更改真实DOM
4. 清除定时器

useEffect Hook 可以看做如下三个生命周期组合

componentDidMount()

componentDidUpdate()

componentWillUnmount()

第一种写法: 
React.useEffect(()=>{
      // 相当于 componentDidUpdate()
   		// 监视所有的数据一旦数据发生变化就调用该函数
   		console.log('@');
 })


第二种写法:
React.useEffect(()=>{
      // 相当于 componentDidUpdate()
   		// 第二个函数可以传入一个数组,数组内可以指定监视某个属性
  		// 监视的属性一旦发生变化就调用该函数
   		console.log('@');
 },[count])


第三种写法:
React.useEffect(()=>{
   // 如果只写一个数组那么就表示谁也不监视
  // 只在初始化的时候执行一次,相当于componentDidMount()
   console.log('@');
},[])


第四种写法:
  React.useEffect(()=>{
       return ()=>{
         // 该函数中只有在组件将要被卸载的时候才会执行
         // 相当于componentWillUnmount()
        	console.log('@');
       }
},[])

13.4 Ref hook

Ref Hook 作用 :可以在函数组件中存储/查找组件内的标签或任意其它数据

语法:const refContainer = React.useRef()

用法和React.createRef()一样

import React, { Component } from 'react'

export default function Demo(){
    // 创建一个存放ref的容器
    const inpRef = React.useRef()
    
    const tip = () =>{
        alert(inpRef.current.value)
    }

    return (
        <div>
            <input type="text" ref={inpRef} />
            <button onClick={tip}>alert</button>
        </div>
    )
}

13.5 useCallback(记忆函数)

作用:防止组件重新渲染时,导致函数重新进行创建,对函数起到缓存作用

根据下面这个案例,不管是修改数值还是修改名字,只要一修改那么整个函数式组件就会重新被渲染, 函数就会被重新创建声明,useCallBack( )就是为了解决这个问题而诞生,可以提高性能优化

import React, { useState, useCallback } from 'react'

export default function CallBack() {
    const [count, setCount] = useState(0)
    const [name,setName] = useState('Jack')
    /*
        useCallback()可以传入两个参数
            - 第一个参数就是我们所写的逻辑
            - 第二个参数就是逻辑中所依赖的属性
        函数在第一次创建的时候就被缓存,只有所依赖的属性发生
        变化才会重新创建声明函数
     */
    const handleAdd = useCallback(
        () => {
            setCount(count + 1 )
        },
        [count]
    )

    const modifyName = useCallback(
        () =>{
            setName('LiHua')
        },[]
    )

    return (
        <div>
            <h2>当前的值为:{count}</h2>
            <button onClick={() => { handleAdd() }}>add</button>
            <h2>{name}</h2>
            <button onClick={modifyName}>点击修改名字</button>
        </div>
    )
}


13.6 useMemo (记忆组件)

useCallback的功能完全可以由useMemo所替代

那么它们之间的区别在于哪里呢?

  1. 写法

    useCallback(fn,[attr])   
    useMemo(()=> fn, [attr])
    
  2. 用法

    useCallback不会执行第一个参数中的函数,而是直接将该函数返回,而useMemo会执行第一个参数中的函数并且将函数执行的结果返回给你,学过Vue的小伙伴应该就知道这个相当于Vue中计算属性

  3. 使用场景

    useCallback常用于记忆事件函数,而useMemo更适合通过一个函数计算得到一个确定的值

    import axios from 'axios'
    import React,{useState,useMemo,useEffect,useCallback} from 'react'
    
    export default function UseMemo() {
      const [inpVal,setInpVal] = useState('')
      const [list,setList] = useState([])
    
      useEffect(()=>{
        axios({
            url:'https://m.maizuo.com/gateway?cityId=310100&ticketFlag=1&k=5006381',
            headers:{
                'X-Client-Info': '{"a":"3000","ch":"1002","v":"5.2.1","e":"1660449552376256314998785","bc":"310100"}',
                'X-Host': 'mall.film-ticket.cinema.list'
            }
        }).then((value)=>{
            setList(value.data.data.cinemas)
        }).catch((error)=>{
            console.log(error);
        })
      },[])
    
      // 处理搜索
      const handleSearch = useCallback(
        (e) =>{
            setInpVal(e.target.value)
          },[]
      )
    
      // 筛选符合条件的内容
      const filterData = useMemo(()=>{
        return list.filter((item)=>{
            return item.name.toUpperCase().includes(inpVal.toUpperCase()) || item.address.toUpperCase().includes(inpVal.toUpperCase())
        })
      },[list,inpVal])
    
      return (
        <div>
            <input type="text"  onChange={handleSearch}/>
            <ul>
                {
                    filterData.map((item)=>{
                        return (
                            <li key={item.cinemaId}>
                                <h3>{item.name}</h3>
                                <h5>{item.address}</h5>
                            </li>
                        )
                    })
                }
            </ul>
        </div>
      )
    }
    
    

13.7 useContext

作用:适用于祖先和后代间通信

import React ,{createContext,useContext}from 'react'

// 第一步: 创建context对象
const GlobalContext = createContext()
export default function UseContextTest() {
  return (
        // 第二步: GlobalContext.Provider包裹祖先,让他成为供应商
        // value属性:传入数据
        <GlobalContext.Provider value={{
            info:'这是祖先传递的消息',
            message:()=>{
                console.log('这是祖先传递的方法');
            }
        }}>
            <div style={{padding:'10px',background:'green'}}>
                <h2>我是祖先</h2>
                <Father></Father>
            </div>
        </GlobalContext.Provider>
  )
}



function Father() {
  return (
    <div style={{padding:'10px',background:'pink'}}>
        <h2>我是儿子</h2>
        <Son></Son>
    </div>
  )
}

function Son() {

  // 第三步:通过useContext(context对象)
  const value = useContext(GlobalContext)
  return (
    <div style={{padding:'10px',background:'red'}}>
        <h2>我是孙子</h2>
        <h4>{value.info}</h4>
        <h4>{value.message()}</h4>
    </div>
  )
}


13.8 useReducer

作用:用于状态管理,和redux作用一样,也是根据redux所创造出来的hook,那么它需要配合useContext一起使用

import React,{useReducer} from 'react'

export default function UseReducer() {
  const initState = {count:0}
  /*
        reducer处理函数可以接收到两个参数
            - 第一个参数:之前状态的值
            - 第二个参数:所派发的action
                - action是一个对象里面存放type和data
   */
  const reducer = (previousState=initState,action)=>{
    const {type,data} = action
    switch (type) {
        case 'plus':
            return {count:previousState.count + data}
        case 'subtract':
            return {count:previousState.count - data}
        default:
            return previousState
    }
  }
   /*
        useReducer可以接收到两个参数
            - 第一个参数:总状态
            - 第二个参数:dispatch用来派发action
        useReducer需要传入到两个参数
            - reducer:处理函数
            - initState:初始化状态

   */
  const [state,dispatch] = useReducer(reducer,initState)
  return (
    <div>
        <h2>当前的值为:{state.count}</h2>
        <button onClick={()=>{
            dispatch({type:'plus',data:1})
        }}> +1 </button>
        <button onClick={()=>{
            dispatch({type:'subtract',data:1})
        }}> -1 </button>
    </div>
  )
}


13.9 自定义hook

自定义 Hook 是一个函数,其名称以 “use” 开头,函数内部可以调用其他的 Hook。

其实本质上就是提取公共部分的逻辑,对其进行函数封装

import {useState,useEffect} from 'react'
import axios from 'axios'
export default function useGetData() {
    const [getData,setData] = useState([]) 
    useEffect(()=>{
        axios({
            url: 'https://m.maizuo.com/gateway?cityId=350600&ticketFlag=1&k=8644263',
            headers: {
                'X-Client-Info': '{"a":"3000","ch":"1002","v":"5.2.1","e":"1660449552376256314998785","bc":"350600"}',
                'X-Host': 'mall.film-ticket.cinema.list'
            }
        }).then((value) => {
            setData(value.data.data.cinemas)
        }).catch((error) => {
            console.log(error)
        })
    },[])

    return getData
}


总结

以上就是今天要讲的内容,希望对大家有所帮助!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值