Hook

316 阅读6分钟

Hook

1. Hook的介绍

  1. 【什么是Hook】,在react中,有了Hook,使得函数组件,可以像类组件一样,拥有自己的状态,以及一些声明周期函数

  2. 【为什么需要Hook】

    • 学习的成本
    • 数据共享,通过使用【redux】
    • 多个业务逻辑,可能存在同一个声明周期函数中
    • 只能在函数中进行使用
  3. 使用了【Hook】大大的简化了代码量,我们知道,在react很久之前是没有Hook,但是是通过编写类组件,但是编写类组件,代码逻辑很多,还有【this】的问题,导致在书写类组件的时候比较的麻烦,容易出错,但是【hook】的出现,解决了这种问题,【Hook】没有this这一说,只能用在函数组件里面

2. useState设置组件状态

在函数组件,为函数组件保存状态

  1. 参数:保存状态的初始值,可以是复杂数据类型
  2. 返回值:【useState】的返回值是一个数组,数组内包含两个值,第一个值是可以用来获取存贮在【useState】里面的初始值,第二个是用来修改状态值的方法
import { useState } from 'react'

function App() {
  const [ state,setState ] = useState(0)
  return (
    <div>{ state }</div>
  )
}
export default App

【注意点】:

  1. 在一个组件的内部,可以多次的使用【useState】,给组件定义多个状态
  2. 在初始【useState】的时候,初始值可以是复杂数据类型
import { useState } from 'react'

function App() {
  const [ state,setState ] = useState([{
    name:'测试1',
    id: 1
  },{
    name:'测试2',
    id: 2
  },{
    name:'测试3',
    id: 3
  }])
  
  return (
    <div>
      <ul>
        {
        	state.map(item => {
          	return (
            	<li key={item.id}>{ item.name }</li>
            )
          })
        }
      </ul>
    </div>
  )
}
export default App
  1. 【useState】是一个异步操作,如果更改了初始的值,但是想要拿到更改的值,需要给【setState】传入一个函数,并且接收一个参数,拿到修改的值
setState((pre) => {
    pre就是上一次处理之后的值,一个开始就是初始值,第二次就是上一次修改的值
})
  1. 如同【类组件中的状态一样】,如果是复杂数据类型,是不能进行直接修改的,需要进行深拷贝一份或者是使用【setPersonState】多数据进行操作
setPersonState({
     参数一是原来的值
    ...state,
     参数二是具体操作哪一个值,直接覆盖原来的值
    name: '小明'
})

【对原有的数据深拷贝】
JSON.parse(JSON.toStrinf(原始数据))

3. useEffect

  1. 【useEffect】是一个三个声明周期函数的结合体,他有三个阶段的声明周期函数,【挂载,更新,卸载】,集成个三个声明周期钩子函数。
  2. 可以使用【useEffect】方法,去发送网络请求,当组件更新的时候去执行
import React,{ useEffect } from 'react'

function App() {
	
  useEffect(() => {
  	console.log('组件怪哉于更新操作')
    
    return () => {
    	console.log('组件被卸载的时候会触发函数')
    }
  })
  
  return (
  	<div></div>	
  )
}

3.1 useEffect的注意点

  1. 组件更新于卸载都会去执行【useEffect】,当组件内部的数据的改变,也会触发组件的卸载,在组件更新的时候,是将原有的组件进行卸载,然后在重新挂载

  2. 【解决方式】,在【useEffect】中,会传入第二个参数,第二个参数是依赖的数据,如果某一个数据发生了变化,才会更新

  3. 【useEffect】的第二个参数最主要的是给【useEffect】做性能优化的

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

function App() {
	const [ state,setState ] = useState(0)
  useEffect(() => {
  	console.lgo('当依赖的数据发生了变化,才会更新')
  },[state])  【 [state]是useEffect组件依赖的数据,传递数据的格式是数组 】
  
  return (
  	<div>
    	<button onClick={setState(state + 1)}> 点击改变 </button>
    </div>	
  )
}
  1. 一般情况写使用【useEffect】去发送网络请求,获取数据

3. useContext 待更新

4. useReducer 待更新

5. useCallback

  1. 【useCallback】的出现,是为了做性能优化的,当子组件需要改变父组件里的状态,但是父组件里面的状态更改,不希望子组件重新进行渲染

  2. 【useCallback】的返回值是一个函数

  3. 图片中的【memo】是属于高阶组件,用于函数组件重复渲染使用的,【父组件给子组件传递事件,子组件通过事件修改父组件里面的值,如果父组件里面的某一个状态更改了,但是不希望子组件被重新进行渲染,无论父组件内部数据怎样的变化,只要是通过子组件修改的数据没有改变,子组件就不会重新渲染】

  4. 【useCallback】可以传入第二个参数,只有第二个参数发生了改变就会重新被执行

6. useMemo

  1. 【useMemo】也是做性能优化的,用于发杂的计算使用【useMemo】进行性能优化
  2. 【useMemo】的返回值是一个具体的值,他和【useCallback】相似,但是他们的返回值不同,一个是返回一个函数,一个返回的是具体的值

7. useRef获取DOM元素

  1. 【useRef】,在react中,在函数组件中,可以通过【useRef】获取DOM元素
function Count (props) {
  const refInput = useRef(null)
  
  // 通过事件,操作获取的元素
  const handload = (props) => {
    props.appCount(refInput.current.value)
  }
  return (
    <>
      <input type='text' ref={refInput} />
      <button onClick={()=>{handload(props)}}>添加</button>
    </>
  )
}

7.1 父组件获取子组件元素

import { forwardRef,useRef } from 'react'

function Home(props,oInput) {
    return (
 	<div>
          <impot ref={ oInput } />
        </div>   	
    )
}
// 使用forwardRef对内部的组件进行包裹
const ForwardHome = forwardRef(Home)

function App() {
    const ForwardHome = useRef()
    
    return (
    	<div>
          <userHome ref={ oInput }>
        </div>
    )
}

8. useImperativeHandle

  1. 拦截操作,不需要外部直接修改组件,不希望子组件内部的所有都可以被修改或者是操作等
function Home(props,oHome) {
  // 获取当前组件内部的元素,进行操作
  const oInput = useRef()
  
  
  // 参数一是当前操作的元素
  useImperativeHandle(oHome,()=> {
    // 这里的返回值是什么,在app组件打印的就是什么
    return {
      // 在这里操作元素,不想让app拿到元素想做什么做什么,只需要我自己操作完返回出去
      setValue: function () {
        oInput.current.value="这是子组件自己修改的"
      }
    }
  })
  return (
    <>
      <h2>Home组件</h2>
      <input ref={oInput}/>
    </>
  )
}

【父组件获取子组件内部的元素先用forwardRef对子组件进行包裹】
const ForwardHome = forwardRef(Home)

function App() {
  const oHome = useRef()
  function btn() {
    console.log(oHome);
    // 这里就无需要做,直接调用组件返回过来的参数
    oHome.current.setValue()
  }

  return (
    <div>
     <!-- 在这里,相当于通过属性给子组件传递数据,但是组件接收的时候是将他单拿出来的,
     不是在props里,在组件内部在将接收的参数当做ref进行使用 -->
     <ForwardHome ref={oHome} />
     <button onClick={ ()=> { btn() } }>+</button>
    </div>
  );
}

export default App;

9. 自定义HOOK

  1. 很多情况下,两个组件内部的操作是相同的,但是只是操作的元素是不同的,如果写两份相同的代码比较繁琐,并且消耗性能,这时可以使用自定义hook函数进行实现

  2. 在定义hook函数的时候,在函数明前面加上一个use,react就会认为是一个钩子函数

function useAddEvebtListenter(name) {
  useEffect(()=> {
    console.log(name,'挂载与更新');
    return () => {
      console.log('组件被卸载');
    }
  })
}
----- 直接在组件里面进行使用,也可以传递参数
function Home() {
  useAddEvebtListenter('home')
  return (
    <div>Home组件</div>
  )
}

10. useDispatch

import {useDispatch} from 'react-redux'

const dispatch = useDispatch() 【 通过useDispatch拿到dispatch对象,然后触发actions 】

11. useSelector 待更新