关于reactjs:反应:useState或useRef?

React: useState or useRef?

我正在" Hooks FAQ "中阅读有关React useState()useRef()的信息,我对一些似乎同时具有useRef和useState解决方案的用例感到困惑,并且我\\'我不确定哪种方法正确。

从" Hooks FAQ "中获取有关useRef()的信息:

"The useRef() Hook isn’t just for DOM refs. The"ref" object is a generic container whose current property is mutable and can hold any value, similar to an instance property on a class."

使用useRef():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Timer() {
  const intervalRef = useRef();

  useEffect(() => {
    const id = setInterval(() => {
      // ...
    });
    intervalRef.current = id;
    return () => {
      clearInterval(intervalRef.current);
    };
  });

  // ...
}

使用useState():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Timer() {
  const [intervalId, setIntervalId] = useState(null);

  useEffect(() => {
    const id = setInterval(() => {
      // ...
    });
    setIntervalId(id);
    return () => {
      clearInterval(intervalId);
    };
  });

  // ...
}

两个示例都将具有相同的结果,但是哪个示例更好-为什么?


两者之间的主要区别是:

useState导致重新渲染,useRef不会重新渲染。

它们之间的共同点是,useStateuseRef都可以在重新渲染后记住它们的数据。因此,如果变量是决定视图图层渲染的变量,请使用useState。否则使用useRef

我建议阅读这篇文章。


基本上,在这种情况下,我们使用UseState,其中state的值应通过重新渲染来更新。

当您希望信息在组件的生命周期内持续存在时,可以使用UseRef,因为它不适用于重新渲染。


如果存储间隔ID,则唯一可以做的就是结束间隔。更好的是存储状态timerActive,这样您就可以在需要时停止/启动计时器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Timer() {
  const [timerActive, setTimerActive] = useState(true);

  useEffect(() => {
    if (!timerActive) return;
    const id = setInterval(() => {
      // ...
    });
    return () => {
      clearInterval(intervalId);
    };
  }, [timerActive]);

  // ...
}

如果要在每个渲染器上更改回调,则可以使用ref更新每个渲染器上的内部回调。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function Timer() {
  const [timerActive, setTimerActive] = useState(true);
  const callbackRef = useRef();

  useEffect(() => {
    callbackRef.current = () => {
      // Will always be up to date
    };
  });

  useEffect(() => {
    if (!timerActive) return;
    const id = setInterval(() => {
      callbackRef.current()
    });
    return () => {
      clearInterval(intervalId);
    };
  }, [timerActive]);

  // ...
}