一、useRef
useRef共有两种用法,获取子组件的实例(只有类组件可用),在函数组件中的一个全局变量,不会因为重复 render 重复申明, 类似于类组件的 this.xxx。
1,获取子组件实例
useRef 在使用的时候,可以传入默认值来指定默认值,需要使用的时候,访问 ref.current 即可访问到组件实例:
1 // 使用 ref 子组件必须是类组件
2 class Children extends PureComponent {
3 render () {
4 const { count } = this.props
5 return (
6 <div>{ count }</div>
7 )
8 }
9 }
10 function App () {
11 const [ count, setCount ] = useState(0)
12 const childrenRef = useRef(null)
13 const onClick = useMemo(() => {
14 return () => {
15 console.log(childrenRef.current)
16 setCount((count) => count + 1)
17 }
18 }, [])
19 return (
20 <div>
21 点击次数: { count }
22 <Children ref={childrenRef} count={count}></Children>
23 <button onClick={onClick}>点我</button>
24 </div>
25 )
26 }
2,类组件属性
有些情况下,我们需要保证函数组件每次 render 之后,某些变量不会被重复申明,比如说 Dom 节点,定时器的 id 等等,在类组件中,我们完全可以通过给类添加一个自定义属性来保留,比如说 this.xxx, 但是函数组件没有 this,自然无法通过这种方法使用,有的朋友说,我可以使用useState 来保留变量的值,但是 useState 会触发组件 render,在这里完全是不需要的,我们就需要使用 useRef 来实现了,具体看下面例子:
1 function App () {
2 const [ count, setCount ] = useState(0)
3 const timer = useRef(null)
4 let timer2
5 useEffect(() => {
6 let id = setInterval(() => {
7 setCount(count => count + 1)
8 }, 500)
9 timer.current = id
10 timer2 = id
11 return () => {
12 clearInterval(timer.current)
13 }
14 }, [])
15 const onClickRef = useCallback(() => {
16 clearInterval(timer.current)
17 }, [])
18 const onClick = useCallback(() => {
19 clearInterval(timer2)
20 }, [])
21 return (
22 <div>
23 点击次数: { count }
24 <button onClick={onClick}>普通</button>
25 <button onClick={onClickRef}>useRef</button>
26 </div>
27 )
28 }
二、useImperativeHandle
useImperativeHandle 可以让你在使用 ref 时自定义暴露给父组件的实例值,说简单点就是,子组件可以选择性的暴露给副组件一些方法,这样可以隐藏一些私有方法和属性,官方建议,useImperativeHandle应当与 forwardRef 一起使用,具体如何使用看下面例子
1 function Child (props, ref) {
2 const child = useRef()
3 const introduce = useCallback (() => {
4 console.log('i can sing, jump, rap, play basketball')
5 }, [])
6 useImperativeHandle(ref, () => ({introduce}));
7 return (
8 <div ref={child}> { props.count }</div>
9 )
10 }
11 const ChildChild = forwardRef(Child)
12 function App () {
13 const [ count, setCount ] = useState(0)
14 const childRef = useRef(null)
15 const onClick = useCallback (() => {
16 setCount(count => count + 1)
17 childRef.current.introduce()
18 }, [])
19 return (
20 <div>
21 点击次数: { count }
22 <ChildChild ref={childRef} count={count}></ChildChild>
23 <button onClick={onClick}>点我</button>
24 </div>
25 )
26 }