有些组件可能需要控制和同步 React 之外的系统。例如,你可能需要使用浏览器 API 聚焦输入框,或者在没有 React 的情况下实现视频播放器,或者连接并监听远程服务器的消息。
使用 ref 引用值
当你希望组件“记住”某些信息,但又不想让这些信息 触发新的渲染 时,你可以使用 ref:
const ref = useRef(0);
与 state 一样,ref 在重新渲染之间由 React 保留。但是,设置 state 会重新渲染组件,而更改 ref 不会!你可以通过 ref.current
属性访问该 ref 的当前值。
function handleClick() {
ref.current = ref.current + 1;
alert('你点击了 ' + ref.current + ' 次!');
}
使用 ref 操作 DOM
由于 React 会自动更新 DOM 以匹配渲染输出,因此组件通常不需要操作 DOM。但是,有时可能需要访问由 React 管理的 DOM 元素——例如聚焦节点、滚动到此节点,以及测量它的尺寸和位置。React 没有内置的方法来执行此类操作,所以需要一个指向 DOM 节点的 ref 来实现。
const inputRef = useRef(null);
function handleClick() {
inputRef.current.focus();
}
使用 Effect 实现同步
与处理特定事件的事件处理程序不同,Effect 在渲染后运行一些代码。使用它将组件与 React 之外的系统同步。
useEffect(() => {
console.log(isPlaying)
}, [isPlaying]);
许多 Effect 也会自行“清理”。
useEffect(() => {
const connection = createConnection();
connection.connect();
return () => connection.disconnect();
}, []);
你可能不需要 Effect
Effect 是 React 范式中的一种脱围机制。它们可以“逃出” React 并使组件和一些外部系统同步。如果没有涉及到外部系统(例如,需要根据一些 props 或 state 的变化来更新一个组件的 state),不应该使用 Effect。移除不必要的 Effect 可以让代码更容易理解,运行得更快,并且更少出错。
有两种常见的不必使用 Effect 的情况:
- 不必为了渲染而使用 Effect 来转换数据。
- 不必使用 Effect 来处理用户事件
响应式 Effect 的生命周期
Effect 的生命周期不同于组件。组件可以挂载、更新或卸载。Effect 只能做两件事:开始同步某些东西,然后停止同步它。如果 Effect 依赖于随时间变化的 props 和 state,这个循环可能会发生多次。
移除 Effect 依赖
不必要的依赖关系可能会导致 Effect 运行过于频繁,甚至产生无限循环。删除它们的方式取决于具体情况。
使用自定义 Hook 复用逻辑
React 有一些内置 Hook,例如 useState
,useContext
和 useEffect
。为了实现效果,可以根据应用需求创建自己的 Hook。把 Effect 包裹进自定义 Hook 可以准确表达你的目标以及数据在里面是如何流动的。