- ReactJS 菜鸟教程
- ReactJS 教程
- ReactJS - 简介
- ReactJS - 安装
- ReactJS - 特性
- ReactJS - 优点和缺点
- ReactJS - 架构
- ReactJS - 创建 React 应用程序
- ReactJS - JSX
- ReactJS - 组件
- ReactJS - 嵌套组件
- ReactJS - 使用组件
- ReactJS - 组件集合
- ReactJS - 样式
- ReactJS - 属性(props)
- ReactJS - 使用属性创建组件
- ReactJS - props 验证
- ReactJS - 构造函数
- ReactJS - 组件生命周期
- ReactJS - 事件管理
- ReactJS - 创建事件感知组件
- ReactJS - 在Expense Manager APP中引入事件
- ReactJS - 状态管理
- ReactJS - 状态管理 API
- ReactJS - 无状态组件
- ReactJS - 使用 React Hooks 进行状态管理
- ReactJS - 使用 React 钩子的组件生命周期
- ReactJS - 组件的布局
- ReactJS - 分页
- ReactJS - Material 用户界面
- ReactJS - Http 客户端编程
- ReactJS - 表单编程
- ReactJS - 受控组件
- ReactJS - 不受控制的组件
- ReactJS - Formik
- ReactJS - 条件渲染
- ReactJS - 列表
- ReactJS - 键
- ReactJS - 路由
- ReactJS - 冗余
- ReactJS - 动画
- ReactJS - 引导程序
- ReactJS - 地图
- ReactJS - 表格
- ReactJS - 使用 Flux 管理状态
- ReactJS - 测试
- ReactJS - CLI 命令
- ReactJS - 构建和部署
- ReactJS - 示例
- ReactJS - 钩子简介
- ReactJS - 使用 useState
- ReactJS - 使用 useEffect
- ReactJS - 使用 useContext
- ReactJS - 使用 useRef
- ReactJS - 使用 useReducer
- ReactJS - 使用 useCallback
- ReactJS - 使用 useMemo
- ReactJS - 自定义钩子
- ReactJS - 可访问性
- ReactJS - 代码拆分
- ReactJS - 上下文
- ReactJS - 错误边界
- ReactJS - 转发引用
- ReactJS - 片段
- ReactJS - 高阶组件
- ReactJS - 与其他库集成
- ReactJS - 优化性能
- ReactJS - 分析器 API
- ReactJS - 门户
- ReactJS - 没有 ES6 ECMAScript 的 React
- ReactJS - 没有 JSX 的 React
- ReactJS - 协调
- ReactJS - 引用和 DOM
- ReactJS - 渲染属性
- ReactJS - 静态类型检查
- ReactJS - 严格模式
- ReactJS - Web 组件
- ReactJS - 日期选择器
- ReactJS - Helmet
- ReactJS - 内联样式
- ReactJS - 属性类型
- ReactJS - 浏览器路由器
- ReactJS - DOM
- ReactJS - 旋转木马
- ReactJS - 图标
- ReactJS - 表单组件
- ReactJS - 参考 API
ReactJS - useImperativeHandle 钩子
useImperativeHandle 是 React 18 中引入的一个 React Hook。通过此钩子,我们可以自定义作为子组件的 ref 公开的句柄。当我们需要立即连接子组件时,这非常有用,这意味着我们希望立即访问和调用子组件上的方法或属性。
语法
useImperativeHandle(ref, createHandle, optional_dependency)
参数
- ref - 这是一个特殊的工具,可以帮助我们连接子组件。当我们在 forwardRef 的帮助下创建子组件时,它被接收为第二个参数。
- createHandle - 这是一组关于我们希望能够对子组件执行的操作的指令。这是我们从 useImperativeHandle 返回的内容。
- optional _dependencies - 我们需要列出我们在 createHandle 部分中使用的所有内容(如 props、state 和变量)。因此,React 会检查这些事情,并确保它们不会意外改变。如果他们这样做,它将更新我们的特殊工具。
返回值
此方法返回 undefined。
如何使用它?
我们可以在组件的顶层使用“useImperativeHandle”来自定义它公开的 ref 句柄 -
import { forwardRef, useImperativeHandle } from 'react';
const MyComp = forwardRef(function MyComp(props, ref) {
useImperativeHandle(ref, () => {
return {
// the methods we want in our code ...
};
}, []);
例子
所以我们可以用两种不同的方式使用这个钩子。首先,通过创建可用于父组件的自定义 ref 句柄,其次通过公开我们自己的命令式方法。我们将进一步逐一讨论这两种方法。
使自定义 ref 句柄可供父组件使用
默认情况下,React 组件不提供对底层 DOM 元素的直接访问。我们必须使用 forwardRef 来允许父组件访问 ;input>子组件中的 DOM 节点。
import { forwardRef } from 'react';
const InputComp = forwardRef(function InputComp(props, ref) {
return <input {...props} ref={ref} />;
});
此代码会将实际的 <input> DOM 节点返回给 InputComp 的引用。
有时我们不想暴露完整的 DOM 节点,而只想暴露其方法或属性的一部分。例如,聚焦和滚动子组件而不暴露整个 DOM 节点。我们可以借助 useImperativeHandle 钩子来自定义暴露的手柄。
例如
import { forwardRef, useImperativeHandle } from 'react';
const InputComp = forwardRef(function InputComp(props, ref) {
useImperativeHandle(ref, () => ({
focus() {
inputRef.current.focus();
},
scrollIntoView() {
inputRef.current.scrollIntoView();
},
}), []);
return <input {...props} />;
});
在上面的示例中,我们正在修改父组件的公开句柄。InputComp 的 focus 和 scrollIntoView 方法可以由父组件调用。但它无法直接访问 DOM 节点<input>。
示例 - 理解此钩子的简短应用程序
import React, { forwardRef, useImperativeHandle, useRef, useState } from 'react';
const Counter = forwardRef(function Counter(props, ref) {
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1);
};
const reset = () => {
setCount(0);
};
useImperativeHandle(ref, () => ({
increment,
reset,
}), []);
return (
<div>
<p>Counter: {count}</p>
</div>
);
});
function App() {
const counterRef = useRef();
const handleIncrement = () => {
counterRef.current.increment();
};
const handleReset = () => {
counterRef.current.reset();
};
return (
<div>
<Counter ref={counterRef} />
<button onClick={handleIncrement}>Increment Count</button>
<button onClick={handleReset}>Reset</button>
</div>
);
}
export default App;
输出
示例 - 揭示我们自己的命令式方法
在组件中,我们可以创建自己的自定义方法并将它们提供给其父方法。这些自定义方法不必与 HTML 元素的内置方法相同。
想象一下,我们有一个 InputForm 组件,它显示一个简单的输入字段组件 (InputForm),当按下按钮时,可以滚动到视图中并聚焦该组件。当我们在名为 App 的父组件中单击一个按钮时,将在输入字段上执行此方法,使其滚动到视图中并获得焦点。
import React, { forwardRef, useRef, useImperativeHandle } from 'react';
const InputForm = forwardRef((props, ref) => {
const inputRef = useRef(null);
useImperativeHandle(ref, () => ({
scrollAndFocus() {
inputRef.current.scrollIntoView();
inputRef.current.focus();
}
}), []);
return <input type="text" ref={inputRef} placeholder="Type here..." />;
});
function App() {
const inputRef = useRef();
const handleButtonClick = () => {
inputRef.current.scrollAndFocus();
};
return (
<div>
<button onClick={handleButtonClick}>Scroll and Focus</button>
<InputForm ref={inputRef} />
</div>
);
}
export default App;
在上面的示例中,我们演示了如何使用 forwardRef 和 useImperativeHandle 来滚动和关注输入字段。
总结
在版本 18 中,useImperativeHandle 是一个有用的 React Hook,它允许通过更改 ref 立即与子组件交互。当我们需要快速访问子组件的功能或属性时,它很有用。通过使用这个钩子,我们可以创建一个连接并定义我们想要在子组件上执行的操作,在需要时提供顺畅的通信和更新,而方法返回未定义。