前言
react hooks 是 React 16.8 的新增特性。 它可以让我们在函数组件中使用 state 、生命周期以及其他
react特性,而不仅限于 class 组件。react hooks 的出现,标示着
react中不会在存在无状态组件了,只有类组件和函数组件。具体可查看官网。
优势:
函数组件不能使用state,遇到交互更改状态等复杂逻辑时不能更好地支持,hooks让函数组件更靠近class组件,拥抱函数式编程。
解决副作⽤问题,hooks出现可以处理数据获取、订阅、定时执行任务、手动修改
ReactDOM这些⾏为副作用,进行副作用逻辑。比如useEffect。 更好写出有状态的逻辑重用组件。
让复杂逻辑简单化,比如状态管理:useReducer、useContext。
函数式组件比class组件简洁,开发的体验更好,效率更⾼,性能更好。 更容易发现无用的状态和函数。
useRef介绍
const refContainer = useRef(initialValue);
1
useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref
对象在组件的整个生命周期内保持不变。本质上,useRef 就像是可以在其 .current 属性中保存一个可变值的“盒子”。
然而,useRef() 比 ref 属性更有用。它可以很方便地保存任何可变值,其类似于在 class 中使用实例字段的方式。
这是因为它创建的是一个普通 Javascript 对象。而 useRef() 和自建一个 {current: …}
对象的唯一区别是,useRef 会在每次渲染时返回同一个 ref 对象。请记住,当 ref 对象内容发生变化时,useRef 并不会通知你。变更 .current 属性不会引发组件重新渲染。如果想要在 React
绑定或解绑 DOM 节点的 ref 时运行某些代码,则需要使用回调 ref 来实现。useRef 有什么作用呢,其实很简单,总共有三种用法
作用于Dom元素 获取子组件的实例(只有类组件可用) 在函数组件中的一个全局变量,不会因为重复 render 重复申明, 类似于类组件的
this.xxx useRef使用 作用于Dom元素
const UseRefComp=()=>{
//创建ref
const inputRef=useRef()
const getValue= () => {
//访问ref
console.log(inputRef.current.value) }
//挂载
return (
<div>
<input ref={inputRef} type="text"> <button onClick={getValue}>获取input的
值</button> </div>
) }
获取子组件的实例(只有类组件可用)
// 使用 ref 子组件必须是类组件
class Children extends PureComponent {
render () {
const { count } = this.props
return (
<div>{ count }</div>
)
}
}
function App () {
const [ count, setCount ] = useState(0)
const childrenRef = useRef(null)
// const
const onClick = useMemo(() => {
return () => {
console.log('button click')
console.log(childrenRef.current)
setCount((count) => count + 1)
}
}, [])
return (
<div>
点击次数: { count }
<Children ref={childrenRef} count={count}></Children>
<button onClick={onClick}>点我</button>
</div>
)
}
在函数组件中的一个全局变量,不会因为重复 render 重复申明, 类似于类组件的 this.xxx
简单例子:
function Test(){
const t=useRef(null);
const handleClick = ()=>{
t.current=setTimeout(()=>{
console.log('timer')
},1000)
}
const handleClear = () => clearTimeout(t.current)
return (
<>
<button onClick={handleClick}>start</button>
<button onClick={handleClear}>clear</button>
</>
)}
有些情况下,我们需要保证函数组件每次 render 之后,某些变量不会被重复申明,比如说 Dom 节点,定时器的 id 等等,在类组件中,我们完全可以通过给类添加一个自定义属性来保留,比如说 this.xxx, 但是函数组件没有 this,自然无法通过这种方法使用,有的朋友说,我可以用useState 来保留变量的值,但是 useState 会触发组件 render,在这里完全是不需要的,我们就需要使用 useRef 来实现了,具体看下面例子
function App () {
const [ count, setCount ] = useState(0)
const timer = useRef(null)
let timer2
useEffect(() => {
let id = setInterval(() => {
setCount(count => count + 1)
}, 500)
timer.current = id
timer2 = id
return () => {
clearInterval(timer.current)
}
}, [])
const onClickRef = useCallback(() => {
clearInterval(timer.current)
}, [])
const onClick = useCallback(() => {
clearInterval(timer2)
}, [])
return (
<div>
点击次数: { count }
<button onClick={onClick}>普通</button>
<button onClick={onClickRef}>useRef</button>
</div>
)
}
当我们们使用普通的按钮去暂停定时器时发现定时器无法清除,因为 App 组件每次 render,都会重新申明一次 timer2, 定时器的 id 在第二次 render 时,就丢失了,所以无法清除定时器,针对这种情况,就需要使用到 useRef,来为我们保留定时器 id,类似于 this.xxx,这就是 useRef 的另外一种用法。