forwardRef

`forwardRef` 是 React 提供的一种高级 API,用于在函数组件中转发(forward)`ref` 到子组件的 DOM 元素或类组件。这对于需要直接操作子组件的 DOM 节点或获取子组件实例的情况非常有用。

如何使用`forwardRef`

示例

假设我们有一个自定义的输入框组件 `FancyInput`,我们希望通过父组件能够直接访问这个输入框的 DOM 节点,以便在父组件中调用焦点(focus)等方法。

**1. 创建 `FancyInput` 组件,使用 `React.forwardRef`**

```javascript

import React, { forwardRef } from 'react';

const FancyInput = forwardRef((props, ref) => (

<input ref={ref} type="text" className="fancy-input" {...props} />

));

export default FancyInput;

```

在这个例子中,我们使用 `React.forwardRef` 创建了一个函数组件 `FancyInput`。这个组件接收 `props` 和 `ref` 作为参数,并将 `ref` 转发给内部的 `input` 元素。

**2. 在父组件中使用 `FancyInput` 并直接操作其 DOM 节点**

```javascript

import React, { useRef } from 'react';

import FancyInput from './FancyInput';

function App() {

const inputRef = useRef(null);

const handleClick = () => {

if (inputRef.current) {

inputRef.current.focus();

}

};

return (

<div>

<h1>Forward Ref Example</h1>

<FancyInput ref={inputRef} />

<button onClick={handleClick}>Focus the input</button>

</div>

);

}

export default App;

```

在这个例子中,使用 `useRef` 钩子创建了一个 `ref`,然后将这个 `ref` 传递给 `FancyInput` 组件。调用 `handleClick` 函数时,通过 `ref` 获取到 `FancyInput` 内部的 `input` 元素并使其获得焦点。

组合 `forwardRef` 和 `useImperativeHandle`

有时你可能希望在转发 `ref` 的同时自定义暴露给父组件的实例值。你可以使用 `useImperativeHandle` 钩子来实现这一目的。

示例

**修改 `FancyInput` 组件**

```javascript

import React, { forwardRef, useImperativeHandle, useRef } from 'react';

const FancyInput = forwardRef((props, ref) => {

const inputRef = useRef();

useImperativeHandle(ref, () => ({

focus: () => {

inputRef.current.focus();

},

clear: () => {

inputRef.current.value = '';

}

}));

return <input ref={inputRef} type="text" className="fancy-input" {...props} />;

});

export default FancyInput;

```

在这个例子中,我们使用了 `useImperativeHandle` 钩子来自定义暴露给父组件的实例值。现在父组件可以调用 `focus` 和 `clear` 方法。

**在父组件中使用自定义方法**

```javascript

import React, { useRef } from 'react';

import FancyInput from './FancyInput';

function App() {

const inputRef = useRef(null);

const handleFocus = () => {

if (inputRef.current) {

inputRef.current.focus();

}

};

const handleClear = () => {

if (inputRef.current) {

inputRef.current.clear();

}

};

return (

<div>

<h1>Forward Ref with useImperativeHandle</h1>

<FancyInput ref={inputRef} />

<button onClick={handleFocus}>Focus the input</button>

<button onClick={handleClear}>Clear the input</button>

</div>

);

}

export default App;

```

在这个父组件中,我们可以使用 `ref` 调用 `FancyInput` 组件中定义的 `focus` 和 `clear` 方法。

总结

  • **`forwardRef`**:允许你在函数组件中转发 `ref` ,使得父组件能够访问子组件的 DOM 节点或实例。

  • **`useImperativeHandle`**:配合 `forwardRef` 使用,允许你自定义暴露给父组件的实例值,可以使 `ref` 除了能访问 DOM 节点之外还可以调用自定义方法。

通过这些高级 API ,我们可以在函数组件中灵活地操作子组件的 DOM 节点或实例,并实现更复杂的交互逻辑。

相关推荐
热爱编程的小曾28 分钟前
sqli-labs靶场 less 8
前端·数据库·less
gongzemin39 分钟前
React 和 Vue3 在事件传递的区别
前端·vue.js·react.js
Apifox1 小时前
如何在 Apifox 中通过 Runner 运行包含云端数据库连接配置的测试场景
前端·后端·ci/cd
树上有只程序猿1 小时前
后端思维之高并发处理方案
前端
庸俗今天不摸鱼2 小时前
【万字总结】前端全方位性能优化指南(十)——自适应优化系统、遗传算法调参、Service Worker智能降级方案
前端·性能优化·webassembly
黄毛火烧雪下2 小时前
React Context API 用于在组件树中共享全局状态
前端·javascript·react.js
Apifox2 小时前
如何在 Apifox 中通过 CLI 运行包含云端数据库连接配置的测试场景
前端·后端·程序员
一张假钞2 小时前
Firefox默认在新标签页打开收藏栏链接
前端·firefox
高达可以过山车不行2 小时前
Firefox账号同步书签不一致(火狐浏览器书签同步不一致)
前端·firefox