Skip to content

React useRef 实践指南 #390

@yangchch6

Description

@yangchch6

大家应该熟悉 React ref,它可以用来获取组件实例对象或者是DOM对象。而 useRef 这个 hooks 函数,除了传统的用法之外,还可以“跨渲染周期”保存数据。

useRef 传统用法

获取组件实例对象或者是DOM对象

import React, { useState, useEffect, useRef, useMemo } from 'react';

const Demo = () => {
    const [count, setCount] = useState(0);

    const doubleCount = useMemo(() => {
        return 2 * count;
    }, [count]); // 第二个参数为[]不会更新

    const couterRef = useRef();

    useEffect(() => {
        document.title = `The value is ${count}`;
        console.log(couterRef.current);
    }, [count]); // 第二个参数为[]不会更新
    
    return (
        <>
            <button ref={couterRef} onClick={() => {setCount(count + 1)}}>Count: {count}, double: {doubleCount}</button>
        </>
    );
}
export default Demo

代码中用 useRef 创建了 couterRef 对象,并将其赋给了 button 的 ref 属性。这样,通过访问 couterRef.current 就可以访问到 button 对应的 DOM 对象。

useRef 保存数据

在一个组件中,state 属性可以跨渲染周期,也就是在组件被多次渲染之后依旧不变。但是,state 的问题在于一旦修改了它就会造成组件的重新渲染。

而使用 useRef 来跨越渲染周期存储数据,对它修改是不会引起组件渲染的。

示例1: 保存定时器ID

import React, { useState, useEffect, useMemo, useRef } from 'react';

export default function App(props){
    const [count, setCount] = useState(0);

    const doubleCount = useMemo(() => {
        return 2 * count;
    }, [count]);

    const timerID = useRef();
    
    useEffect(() => {
        timerID.current = setInterval(()=>{
            setCount(count => count + 1);
        }, 1000); 
    }, []);
    
    useEffect(()=>{
        if(count > 10){
            clearInterval(timerID.current);
        }
    });
    
    return (
        <>
            <button onClick={() => {setCount(count + 1)}}>Count: {count}, double: {doubleCount}</button>
        </>
    );
}

在上面的例子中,我用 ref 对象的 current 属性来存储定时器的ID,这样便可以在多次渲染之后依旧保存定时器ID,从而能正常清除定时器。

示例2: 保存上一次的值

import React, { useState, useEffect, useRef } from 'react';

function usePrevious(value){
    const ref = useRef()
    useEffect(() => {
        ref.current = value
    })
    return ref.current
}

const Counter = () => {
    const [count, setCount] = useState(0)
    const preCount = usePrevious(count)
    useEffect(() => {
        setTimeout(() => setCount(10), 1000)
    })
    return <h1> Now: {count}, before: {preCount}</h1>
}

export default Counter

上面代码中,使用了 ref 对象的 current 属性来存储 count 被修改前的值

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions