useRef 简单易懂解析(八)你学会了吗,来试试这些挑战 - 修复无法重新渲染的组件

677 阅读3分钟

这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战

当你希望组件“记住”一些信息,但是你不希望这些信息触发重新 render 的时候,你可以使用 ref,它像一个秘密的“口袋”,用于在组件中存储信息。

后面的文章主要是通过一些例子检验对 ref 的理解,实际在 react 官方博客上可以执行调试,文章主要是分析,可以对照着看:beta.reactjs.org/learn/refer…

系列文章

修复无法重新渲染的组件

挑战 2 - 4:修复无法重新渲染的组件

此按钮应该在显示“On”和“Off”之间切换。但是,它总是显示“Off”。这段代码有什么问题?让我们一起来修复它~

import { useRef } from 'react';

export default function Toggle() {
  const isOnRef = useRef(false);

  return (
    <button onClick={() => {
      isOnRef.current = !isOnRef.current;
    }}>
      {isOnRef.current ? 'On' : 'Off'}
    </button>
  );
}

3

2

1

在这个例子中,ref 的当前值被用来计算 render 时候的输出 {isOnRef.current ? 'On' : 'Off'}。这是一个代码有问题的标志,表明这个信息不应该存储在 ref 中,因为我们前面说到,修改 ref 的 current 值是不会重新触发 render 的,所以这里应该放在 state 中。要修复它的话,我们需要删除 ref 并去使用 state:

import { useState } from 'react';

export default function Toggle() {
  const [isOn, setIsOn] = useState(false);

  return (
    <button onClick={() => {
      setIsOn(!isOn);
    }}>
      {isOn ? 'On' : 'Off'}
    </button>
  );
}

那我们回忆一下 ref 和 state 的区别~

  • 修改 ref 不会触发重新 render,修改 state 会
  • ref 是一个纯对象,他可以通过直接设置 current 属性的方式修改,state 需要通过状态设置函数来修改
  • ref 不能在 re-render 之间读取或写入,这样会导致结果不可控

受控组件和非受控组件

和上面的问题有相关性,我们来看下受控和非受控组件在 React 的区别,和 ref 在里面的使用方式:

  • 受控组件会通过 props 获取它的当前值,并且通过 onChange 之类的回调函数更改的组件的值。父组件通过处理回调和管理自己的 state 来“控制”它,并将新的值通过 props 传递给被控制的组件。你也可以称之为“哑组件(dumb component)”。
  • 非受控组件是一种在组件内部存储自己 state 的组件,你可以在需要时使用 ref 的方式查询 DOM,用来查找它的当前值。这有点像传统的 HTML。

下面是受控组件和非受控组件的例子:

// 受控组件:
<input type="text" value={value} onChange={handleChange} />

// 非受控组件:
<input type="text" defaultValue="foo" ref={inputRef} />
// 使用 `inputRef.current.value` 去获取 <input> 的当前值