ReactJS 教程

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 事件 ReactJS - 状态管理 ReactJS - 状态管理 API ReactJS - 无状态组件 ReactJS - Hooks 进行状态管理 ReactJS - Hooks 的组件生命周期 ReactJS - 布局组件 ReactJS - 分页 ReactJS - Material UI ReactJS - Http 客户端编程 ReactJS - 表单编程 ReactJS - 受控组件 ReactJS - 非受控组件 ReactJS - Formik ReactJS - 条件渲染 ReactJS - 列表 ReactJS - Key 键 ReactJS - 路由 ReactJS - Redux ReactJS - 动画 ReactJS - Bootstrap ReactJS - Map ReactJS - 表格 ReactJS - 使用 Flux 管理状态 ReactJS - 测试 ReactJS - CLI 命令 ReactJS - 构建和部署 ReactJS - 示例

Hooks

ReactJS - Hooks 简介 ReactJS - 使用 useState ReactJS - 使用 useEffect ReactJS - 使用 useContext ReactJS - 使用 useRef ReactJS - 使用 useReducer ReactJS - 使用 useCallback ReactJS - 使用 useMemo ReactJS - 自定义 Hooks

ReactJS 高级

ReactJS - 可访问性 ReactJS - 代码拆分 ReactJS - 上下文 ReactJS - 错误边界 ReactJS - 转发 Refs ReactJS - 片段 ReactJS - 高阶组件 ReactJS - 与其他库集成 ReactJS - 优化性能 ReactJS - Profiler API ReactJS - Portals ReactJS - 不使用 ES6 ECMAScript ReactJS - 不使用 JSX 的 React ReactJS - Reconciliation ReactJS - Refs 和 DOM ReactJS - 渲染道具 ReactJS - 静态类型检查 ReactJS - 严格模式 ReactJS - Web 组件

其他概念

ReactJS - 日期选择器 ReactJS - Helmet ReactJS - 内联样式 ReactJS - PropTypes ReactJS - BrowserRouter ReactJS - DOM ReactJS - 轮播 ReactJS - 图标 ReactJS - 表单组件 ReactJS - 参考 API

ReactJS 有用资源

ReactJS - 快速指南 ReactJS - 备忘录 Axios - 备忘录 ReactJS - 有用资源 ReactJS - 讨论


ReactJS - useImperativeHandle Hook

useImperativeHandle 是 React 18 中引入的 React Hook。此 Hook 允许我们自定义作为子组件的 ref 公开的句柄。当我们需要立即连接子组件时,这非常有用,这意味着我们想要立即访问和调用子组件上的方法或属性。

语法

useImperativeHandle(ref, createHandle,optional_dependency)

参数

  • ref − 这是一个帮助我们连接子组件的特殊工具。当我们借助 forwardRef 创建子组件时,它会作为第二个参数接收。

  • createHandle − 它是一组指令,用于说明我们希望能够对子组件执行的操作。这就是我们从 useImperativeHandle 返回的内容。

  • 可选依赖项 − 我们需要列出我们在 createHandle 部分中使用的所有内容(如 props、state 和变量)。因此,React 将检查这些内容并确保它们不会意外更改。如果发生更改,它将更新我们的特殊工具。

返回值

此方法返回未定义。

如何使用它?

我们可以在组件的顶层使用"useImperativeHandle"来自定义它公开的 ref 句柄 −

import { forwardRef, useImperativeHandle } from 'react';

const MyComp = forwardRef(function MyComp(props, ref) {
   useImperativeHandle(ref, () => {
      return {
         // the methods we want in our code ...
      };
   }, []);

示例

因此,我们可以通过两种不同的方式使用此Hooks(钩子)。首先,创建一个可供父组件使用的自定义 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 Hooks(钩子)自定义暴露的句柄。

例如

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>。

示例 − 简短应用程序以了解此 Hook

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;

输出

counter

示例 − 公开我们自己的命令式方法

在组件中,我们可以创建自己的自定义方法并将它们提供给其父级。这些自定义方法不必与 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 立即与子组件交互。当我们需要快速访问子组件的功能或属性时,它很有用。通过使用这个Hooks(钩子),我们可以创建一个连接并定义我们想要对子组件执行的操作,在需要时提供顺畅的通信和更新,方法返回未定义。

reactjs_reference_api.html