hook简介
- hook 是React 16.8 的新特性,使函数组件更强大
- 优点
- 可以在不编写 class 的情况下使用
state
以及其他的 React 特性 - 解决业务逻辑难拆分的问题
- 方便状态逻辑复用
- 可以在不编写 class 的情况下使用
- 注意点
- hook和class写法共存
- hook只能在函数组件中使用
基础hook
useState
-
为函数组件提供数据状态(state)
-
const [count,setCount] = useState(0) count:使用的数据 setCount:修改数据的对应方法
-
注意点
-
useState的初始参数只会在组件首次渲染时使用,再次更新时会被忽略
-
每次通过
setCount
修改状态都会引起组件重新渲染 -
useState
可以调用多次,每次都是独立的 -
useState
不可以在函数组件之外的地方执行 -
如果初始值需要计算才能得到,那可以使用回调函数写法
-
const [count,setCount] = useState(()=>0)
-
-
useEffect
-
作用
- 发送网络请求
localstorage
操作- 监听数据修改
UI
- 手动修改
DOM
-
执行时机
- 默认状态:首次执行+每次组件更新时执行
- 添加空数组([]) : 首次执行
- 添加需要监听的数据: 首次执行+监听数据变化时执行
-
清除副作用 :数据渲染
UI
之外的操作-
useEffect(()=>{ return()=>{ //清理副作用 //例如:清除定时器等 } })
-
useContext
- 作用:在
hook
下跨组件传递数据 - 实现步骤
- 使用
createContext
创建Context
对象 - 在顶层组件通过
Provider
提供数据 - 在底层组件通过
useContext
函数获取数据
- 使用
额外的 hook
useRef
-
作用:获取真实的
DOM
或者组件实例对象 -
实现步骤
-
导入
useRef
函数 -
执行
useRef
函数并传入 null,返回值为一个对象,内部有一个current属性存放DOM
对象(组件实例) -
通过
ref
绑定获取元素或者组件-
const divRef = useRef() <div ref={divRef}></div>
-
-
useImperativeHandle
-
作用:在使用
ref
时自定义暴露父组件的实例值 -
实现步骤
- 给子组件绑定
useRef
属性 - 在子组件中导入
forwardRef
,包裹子页面顶层组件;包裹后第一个参数是props
属性,第二个参数是ref
属性 - 导入
useImperativeHandle
,有三个参数- 第一个参数:
ref
- 第二个参数: 返回值;需要在父页面操作的dom,
- 第三个参数:数组依赖项;控制
useImperativeHandle
返回值是否刷新
- 第一个参数:
- 补充:
- 导入
useImperativeHandle
后可以通过返回控制子组件的全部ref
; useImperativeHandle
,返回值可以返回多种类型forwardRef
,只能控制一个
- 导入
- 给子组件绑定
-
代码实现
-
//父页面 import {useRef} from "react" import ImperaciveHandle from "@/components/hooks/ImperativeHandle.jsx" const App()=>{ const fatherRef = useRef() return ( <div> // 操作子组件实例 <button onClick={()=> { fatherRef.current.userRef.current.focus() }}>聚焦输入框</button> <button onClick={()=> { fatherRef.current.passwordRef.current.focus() }}>聚焦密码</button> <ImperaciveHandle ref={fatherRef}/> </div> ) } export default App;
-
// 子组件 import { useRef, forwardRef ,useImperativeHandle} from "react" // 1. 使用 forwardRef ,包裹页面组件,包裹后组件参数,第一个是props,第二个是ref const ImperaciveHandle = ({},ref) => { const userRef = useRef() const passwordRef = useRef() // 2.将需要父组件操控的dom,通过 useImperativeHandle 返回 useImperativeHandle(ref,()=>{ // 这里可以返回数组,对象,字符串,jsx等 return { userRef, passwordRef, } //[]:依赖项控制 useImperativeHandle 返回值是否刷新 },[]) return ( <div> <input type="text" placeholder="用户名" ref={userRef} /> <input type="password" placeholder="密码" ref={passwordRef} /> </div> ) } export default forwardRef(ImperaciveHandle)
-
以上通过
useImperativeHandle
实现焦点控制
-
useMemo
-
作用:监听子组件变化来处理事件,优化子组件渲染
-
useMemo
有两个参数,
1. 第一个参数是函数;
2. 第二个参数是数组,用来监听某个状态不改变,状态不改变,函数就不会执行,除了首次渲染时
-
import React, { useState, useMemo } from 'react';
const Child = ({ age, name, children }) => {
//在不用useMemo做处理的时候,只要父组件状态改变了,子组件都会渲染一次;
//用了useMemo可以监听某个状态name,当name变化时候执行useMemo里第一个函数,
console.log('子组件渲染');
function namechange() {
console.log('子组件内部函数');
return name + 'change';
}
//useMemo有两个参数,和useEffect一样,第一个参数是函数,第二个参数是个数组,用来监听某个状态不变化
const changedname = useMemo(() => namechange(), [ name ]);
return (
<div style={{ border: '1px solid' }}>
<p>children:{children}</p>
<p>name:{name}</p>
<p>age:{age}</p>
<br />
{/* 子组件函数 */}
<p>changed:{changedname}</p>
</div>
);
};
const UseMemo = () => {
const [ name, setName ] = useState('张三');
const [ age, setage ] = useState(20);
return (
<div>
<button
onClick={() => {
setname('张三' + new Date().getTime());
}}
>name</button>
<button
onClick={() => {
setage('年龄' + new Date().getTime());
}}
>age</button>
<p>父组件的:{name}--{age}</p>
<Child age={age} name={name}>
{name}的children
</Child>
</div>
);
};
```