什么是Hooks
Hooks从语法上来说是一些函数。这些函数可以用于在函数组件中引入状态管理和生命周期方法。
React Hooks的优点
- 简洁
从语法上来说,写的代码少了 - 上手非常简单
- 基于函数式编程理念,只需要掌握一些JavaScript基础知识
- 与生命周期相关的知识不用学,react Hooks使用全新的理念来管理组件的运作过程
- 与HOC相关的知识不用学,React Hooks能够完美解决HOC想要解决的问题,并且更可靠
- Mobx取代了Redux做状态管理
- 代码复用性更好
- 与Typescript结合更简单
React Hooks的缺点
- 状态不同步
在异步操作的函数中访问的状态还是原来的状态的值 - useEffect依赖问题
当useEffect依赖的数据变多后会导致频繁触发
React Hooks的注意事项
- 命名规范
自定义Hooks的命名一律使用use作为前缀,形如:useXXX - 仅在最外层调用React Hooks
- 仅从react函数中调用react Hooks
在自定义Hooks或者组件中调用Hooks
ref hook
可以在函数式组件中存储/查找组件内的元素或其他数据
useRef
useRef(initialValue)返回一个可变的ref对象,该对象只有一个current属性,初始值为传入的参数initialValue,并且返回的ref对象在组件的整个生命周期内保持不变。
作用:
- 用来获取DOM节点的实例,与React.createRef()作用一样
- 存储渲染周期之间的共享数据
- 获取DOM节点的实例
jsx
import {useRef} from 'react'
function APP(){
const userRef = useRef(null);
const clickButton = ()=>{
if(userRef.current){
console.log(userRef.current);
}
}
return <div>
<input name="username" ref={userRef} />
<button onClick={clickButton}>show</button>
</div>
}
-
存储共享数据
jsximport {useRef,useState} from 'react' function APP(){ const [count,setCount] = useState(0); const countRef = useRef(null); const preCount = countRef.current; useEffect(()=>{ countRef.current = count; }); const clickButton = ()=>{ setCount(count+1); } return <div> <input name="username" /> <button onClick={clickButton}>show</button> </div> }
注意事项
- 组件的每次渲染,useRef的返回值都不变
- ref.current发生变化并不会造成重新渲染
- 不可以在render中更新ref.current的值,否则会导致ref.current的值计算错误
这是因为当其他的数据发生变化时,会导致重新渲染,这时ref.current会更新,这就导致计算错误。 - 元素属性的ref的值不能是useRef返回的对象以外的值
- ref.current的值发生变化不会触发useEffect
forwardRef
当ref作用在一个函数式组件上时不会获取到组件实例。因此需要使用forwardRef。
forwardRef会创建一个React组件,这个组件能够将其接收的ref属性转发到自己的组件树。
forwardRef()的用法是包裹一个组件。
jsx
import {forwardRef,useRef,useEffect} from 'react'
const Child = forwardRef((props,ref)=>{
return <input ref={ref} type="text" />
});
function App(){
const childRef = useRef(null);
useEffect(()=>{
childRef.current.focus();
});
return <>
<Child ref={childRef}></Child>
</>
}
useImperativeHandle
useImperativeHandle允许组件自定义需要暴露的ref数据,是为了解决useRef获取到组件的所有属性和方法的问题。
useImperativeHandle(ref,handle,[deps]):
- ref:需要暴露的ref引用
- handle:是一个函数,返回值会作为ref.current的值
- deps:依赖数据,需要监听的状态
jsx
import {useRef,useImperativeHandle,forwardRef} from 'react'
const Child = forwardRef((props,ref){
useImperativeHandle(ref,()=>{
return {
focus:()=>ref.current.focus()
}
},[props.value]);
retunr <input ref={ref} value={props.value} />
});
function App(){
const childRef = useRef(null);
return <>
<Child ref={childRef}></Child>
</>
}
注意事项
- useImperativeHandle和React.forwardRef必须配合使用,否则在运行的时候会直接报错。
- 使用useImperativeHandle后,可以让父、子组件分别有自己的ref,通过React.forwardRef将父组件的ref传递过来,通过useImperativeHandle方法来自定义开放给父组件的current。