React的Hooks

React Hook

Hook 是 React 16.8 的新增一系列封装函数,它可以让函数组件中可以使用state,跨组件通信,生命周期等React的特性

Hook的意义在于:将函数组件中的业务逻辑抽离出来,保证组件UI的纯净化

内置Hook (10个)


1.useState

定义和修改state [修改state的方法得到的一定是新值]

基本语法:
//定义state和修改state的方法
const [name,setName]=useState<数据类型>(数据默认值)
//定义事件处理程序来修改state
const change=()=>{
    // setName()
    // setName((旧值)=>{return 修改后的值})
}
案例一:定义修改字符串
import Reac, { FC,useState} from "react";
interface IAppProps{}
const App:FC<Partial<IAppProps>>=()=>{
  // todo 定义state和义修改state的方法
  const [name,setName]=useState<string>('篮网')
  // todo  定义事件处理程序
  const set=()=>{setName('掘金')}
  return <div>
    <button onClick={set}>点击</button>
    <p>{name}</p>
  </div>
}
export default App;
案例二:定义修改数值(计数案例)
import Reac, { FC,useState} from "react";
interface IAppProps{}
const App:FC<Partial<IAppProps>>=()=>{
  // todo 定义state和义修改state的方法
  const [count,addCount]=useState<number>(1);
  // todo 定义事件处理程序
 const add=()=>{addCount((n)=>n+1)}
  return <div>
   	 <button onClick={add}> + {count} </button>
  </div>
}
export default App;
案例三:定义修改数值(计数案例)
import Reac, { FC,useState} from "react";
interface IAppProps{}
const App:FC<Partial<IAppProps>>=()=>{
  // todo 定义state和义修改state的方法
  const [count,addCount]=useState<number>(1);
  // todo 定义事件处理程序
 const add=()=>{addCount((n)=>n+1)}
  return <div>
   	 <button onClick={add}> + {count} </button>
  </div>
}
export default App;
案例四:定义修改对象
import Reac, { FC,useState} from "react";
interface IAppProps{}
interface IObj{name:string}
const App:FC<Partial<IAppProps>>=()=>{
  const [obj,setObj]=useState<Partial<IObj>>({})
  const giveObjName=()=>{
      
    // !! 下面的代码不能写 
    // obj.name = 'lakers';
    // setObj(obj);
      
    //  todo1 写法1
    // setObj({name:'篮网'})
    // todo1 写法2
    obj.name='篮网'
    setObj({...obj})
  }

  return <div>
    <button onClick={giveObjName}>给对象值</button>
    <p>{obj.name}</p>
  </div>
}

案例五:定义修改数组
import React, { FC, useState } from "react";
interface IAppProps {}
interface IList {
  id: number;
  task: string;
  flag: boolean;
}
const App: FC<Partial<IAppProps>> = () => {
  // todo 定义state和义修改state的方法
  const [list, setList] = useState<Partial<IList>[]>([]);
  // todo 定义事件处理程序
  const add = (e: any) => {
    if (e.keyCode === 13) {
      const obj = {
        id: list.length + 1,
        task: e.target.value,
        flag: false,
      };
      setList([obj, ...list]);
      e.target.value=''
    }
  };

  return (
    <div>
      <input type="text" onKeyDown={ add } />
      <ul>{list.map((item) => (<li key={item.id}>{item.task}</li>))}</ul>
    </div>
  );
};
export default App;

2.useReducer 定义和修改state

类似于类似 Redux 的功能

  1. 定义state以及修改state

  2. 可以理解为做出来类似vuex的效果

  3. 可以理解它是一个简易版本的状态管理工具

它接收一个如 (state, action) => newState 的 reducer和一个初始化的state,并返回当前的 state 以及与其配套的 dispatch 方法

作者:zidea
链接:https://www.jianshu.com/p/14e429e29798
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

写法一:

  const [state,dispatch]=useReducer(reducer,initialState)

写法二:

  const [state,dispatch]=useReducer((state,action)=>{},初始化的state)

案例:计数案例

流程 button --> add – dispatch发布 —> reducer的action接收 ----> state

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

interface IInitialState{
  count:number
}
const initialState:IInitialState={
  count:0
}
const reducer=(state:any,action:any) => {
  switch (action.type){
    case 'add':
      return {count:state.count+1}
    case 'jian': 
      return {count: state.count - 1 }
    default:
      return initialState
  }
}

const App:FC=() => {
  const [state,dispatch]=useReducer(reducer,initialState)
  const add=()=>{
    dispatch({type:'add'})
  }
  const jian=()=>{
    dispatch({type:'jian'})
  }

  return (
    <div>
      <button onClick={add}>+</button>
      <button onClick={jian}>-</button>
      <p>{state.count}</p>
    </div>
  )
}
export default App

3.useEffect

useEffect是用于实现生命周期功能的,他有3三种用法

语法:

语法: useEffect(callback,[数据])

数据:数据可以多个,可为props,state

**用法1:componentDidMount **

useEffect(() => {}, [])

类似componentDidMount 钩子函数功能 :组件挂载结束

自动执行一次,可以进行真实DOM操作,数据请求发送

用法2:componentDidUpdate

useEffect(() => {}, [数据]) 

类似componentDidUpdate钩子函数功能 :组件更新结束 表示对这个数据做监听

数据改变,就会触发,执行多次

**用法3:componentWillUnmount **

//callback的返回值为一个函数
useEffect(() => {
    return () => {}
}) 
// 第二个参数随意

类似componentWillUnmount 的功能 :组件销毁时触发

4.useLayoutEffect 类似useEffect

 useLayoutEffect
    1. 用法和useEffect一致
    2. useLayoutEffect 解决了什么问题是useEffect解决不了的?
      - 其函数签名与 useEffect 相同,但它会在所有的 DOM 变更之后同步调用 effect。可以使用它来读取 DOM 布局并同步触发重渲染。在浏览器执行绘制之前,useLayoutEffect 内部的更新计划将被同步刷新 
    3. 理解
      - 范围不一致,useLayoutEffect的更大
    4. 什么时候用它?
      - 如果你正在将代码从 class 组件迁移到使用 Hook 的函数组件
      - 我们推荐你一开始先用 useEffect,只有当它出问题的时候再尝试使用 useLayoutEffect。

5.useRef ref绑定

通过ref绑定可以拿到类子组件的数据或方法

ref无法绑定函数子组件,但子组件使用forwardRef高阶组件可以解决

绑定类组件

// 父组件

const 绑定名: any = useRef(null) //拿到子组件实例

绑定名.current.数据/方法   //使用子组件的数据或方法

<子组件  ref={绑定名}> //绑定子组件

绑定函数组件

ref无法绑定函数子组件,可以通过forwardRef高阶组件解决

  • forwardRef

forwardRef 我们称之为 高阶组件[HOC] High Order Component

它是一个函数,接收一个组件作为参数,并返回一个新组件

高阶组件的原理是闭包

// 父组件绑定和使用如绑定类组件

// 子组件导出时,导出新组件
export default React.forwardRef(Hello)

手动封装forwardRe

// 闭包
const HocComp = ( Comp: any ) => {
	return class _ extends React.Component{
 		 render () {
     		return <Comp/>
  		 }
  	}
}

6.usemperativeHandle

和ref绑定搭配,我们将子组件的内容绑定到父组件的ref中

  1. 搭配ref绑定来使用的

  2. 专用于函数组件

  3. 他有两个参数:第一个为ref,第二个为回调函数

  4. 它的返回值就是父组件ref绑定获得的结果

  5. 注意第一个参数ref的类型约定

// ref的类型约定
// ref: React.Ref<unknown>
useImperativeHandle(ref,() => {
    return {可以返回数据或方法}
})

7.useContext 跨组件通信

创建上下文context对象

// src/context/index.ts
import React from 'react'

const ctx = React.creatContext(0)

export default ctx

数据源组件

import ctx from './context'

....
return (
	<ctx.Provide value={money}>
        <接收组件>
    </ctx.Provid>
)

接收组件(类组件)

//引入上下文组件
import {useContext}
import ctx from './context'

//从ctx拿到数据实例
static contextType=ctx;

//使用数据
return(
	<div>{this.context}<div>
)

接收组件(函数组件)

//引入上下问组件
import {useContext}
import ctx from './context'

//从ctx拿到数据实例
const money=useContext(ctx)

//使用数据
return(
	<div>{money}<div>
)

8.useMeno 组件性能优化

问题一: 类组件中通过 shouldComponentUpdate 达到性能优化目的,那么函数组件呢?
解决: Hook ( useCallback useMemo )
问题二: 函数组件 - 重复渲染问题
因为函数组件本身是函数,所以只要数据改变,它就要重新执行自身

总结
state的改变,会引起组件的重复调用,那么渲染就会重复执行,这样会带来性能损耗
解决: useMemo/useCallback

语法:

const memoValue =useMemo(()=>{当监听数据改变时,才执行这里的渲染代码},监听数据)
//该函数会得一个返回值,通常被称为记忆值 

案例:优化函数组件的渲染

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

const App:FC=()=>{
  const [n,setN]=useState<number>(0)
  const [list,setList]=useState<Array<number>>([1,2,3,4])
  const add=()=>{
    setN((n)=>n+1)
  }

  const renderList=()=>{
    console.log('render');
    return list.map((item,index)=>( <li key={index}>{item}</li> ))
  }
  // memoValue为记忆值
  const memoValue= useMemo(() => renderList(), [list])
  const addList=()=>{
    setList(
      [Math.max(...list)+1,...list]
    )}

  return (
    <div>
      <button onClick={add}>+ {n}</button>
      <hr />
      <button onClick={addList}>加一条数据</button>
      <ul>
          {memoValue}
      </ul>
    </div>
  )
}
export default App 

9.useCallback 组件性能优化

父组件将渲染函数传递给子组件,但当父组件数据更新时,会引起子组件不必要的更新,所以可以使用useCallback得到一个返回值为渲染函数的记忆值,使用记忆值来代替传递的渲染函数

useCallback + memo【高阶组件】

// 父组件
import React, { FC, useState, useCallback } from "react";
import Hello from "./Hello";

const App: FC = () => {
  const [count, setCount] = useState<number>(0);
  const [list, setList] = useState<Array<number>>([1, 2, 3, 4]);

  const add = () => {
    setCount((n) => n + 1);
  };

  const renderList = () => {
    console.log('render')
    return list.map((item,index) => <li key={index}> { item } </li>)
  } 
  // todo 得到一个记忆函数
  const memoFunc = useCallback(() => {
    return renderList()
  }, [list])

  return (
    <div>
      <button onClick={add}> + {count} </button> 
      <hr/>
      <Hello memoFunc = { memoFunc } />
    </div>
  );
};

export default App;



// 子组件
import React, { ReactElement,memo } from 'react'

interface Props {
  memoFunc: () => ReactElement[]
}

function Hello({memoFunc}: Props): ReactElement {
  return (
    <div>
      <ul>
        { memoFunc() }
      </ul>
    </div>
  )
}


export default memo(Hello)

10.useDebugValue 自定义Hook起名

给自定义Hook起名[ 谷歌调试插件显示 ]

自定义Hook就是一个封装函数

名字前缀 useXxx

注意: hook不可以嵌套使用

// 自定义Hook   src/hooks/index.ts
import { useDebugValue, useEffect, useState } from "react";
const useDemo=(Flag:boolean)=>{
    const [txt,setText]=useState<string>('');
    useEffect(()=>{
        Flag? setText('进入我心里') :setText('QNMD')
    },[])
    useDebugValue('Flag')
    return txt
}

export {useDemo}

自定义Hook库:

  1. https://ahooks.js.org/zh-CN/
  2. https://github.com/Junscuzzy/useHooks.ts
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值