-
类组件中的 Ref
-
-What-
- 在 React类组件中,ref 是用来 获取组件 或者 DOM元素的引用 的一种机制。通过 Ref ,可以在函数组件中直接访问子组件的实例或者访问 DOM 元素。
-
-
useRef
-
-What-
- React 中的 useRef 是一个 Hook 函数,它可以用来在函数组件中创建一个可变的引用。类似于类组件中的 ref 属性,但有一些不同之处:useRef 可以用来保存任意可变值,而不仅仅是 DOM 元素的引用。useRef返回一个包含一个current属性的对象。这个current属性可以存储任意值,并且在函数组件的多次渲染之间保持不变。
-
-Why-
- 直接操作DOM:有时需要直接访问和操作 DOM 元素
- 测量和布局:当需要精确测量元素尺寸或位置时,ref可以提供直接访问 DOM 的方式
- 表单处理:在处理非受控组件时,ref可以用来获取表单元素的值
- 动画和过渡:在实现复杂的动画或过渡时,可能需要直接操作 DOM 元素
- 性能优化:通过 ref 直接操作 DOM 有时可以避免不必要的重新渲染,从而提高性能
- 访问子组件的属性或方法:某些情况下,需要访问子组件的方法或属性,特别是在使用第三方库时
- 保存可变值:useRef 可以用来存储 在组件重新渲染之间保持不变的可变值,而不触发重新渲染(类似vue的计算属性)
-
-How-
- 基本语法
// 基本语法 import { useRef } from 'react'; function MyComponent() { //初始值可以是任意类型的值 const ref = useRef(initialValue); // ... } - 获取 DOM 操作 DOM
import { useRef, useEffect } from 'react'; function MyComponent() { const inputRef = useRef(); useEffect(() => { inputRef.current.focus(); }, []); return ( <input ref={inputRef} /> ); } - 存储任意值
import { useRef } from 'react'; function MyComponent() { const countRef = useRef(0); function handleClick() { countRef.current += 1; console.log(countRef.current); } return ( <button onClick={handleClick}>Click me</button> ); }
- 基本语法
-
-
React.forwardRef
-
-What-
- forwardRef 会创建一个 React 组件,这个组件能够将其接收的 ref 属性 发到其组件树下的另一个组件中。目的就是希望外层组件可以通过 ref 直接控制内层组件或元素。
-
-Why-
- 在 React里给函数组件直接写 ref 属性时,控制台会报警告
// 父组件 import { useRef } from "react"; import ComChild from "./components/HOC/ComChild1"; export default function App() { const ChildRef = useRef() return ( <div> <ComChild name='demo' ref={ChildRef} /> </div> ); } // 子组件 export default function ComChild(props: { name: string, ref: React.MutableRefObject<undefined> }) { return <div>子组件1 name:{props.name}</div>; }

- 函数组件的设计初衷:React 的函数组件的设计初中是为了简化组件的创建和使用,强调无状态和纯函数的概念。更适合用于展示性组件,而不涉及复杂的实例管理
- 状态管理的不同:函数组件通常使用 React Hooks(如 useState 、useEffect) 来管理状态和副作用,而不是依赖于实例属性和方法。ref 的使用在函数组件中需要通过 useRef 来实现,这与类组件的 ref 使用方式不同。
- 一致性和可维护性:通过React.forwardRef 明确地将 ref 转发到子组件,可以提高代码的一致性和可维护性。这样可以清晰的看到 ref 的传递路径,避免了直接在函数组件中使用 ref 可能带来的混乱。
- 在 React里给函数组件直接写 ref 属性时,控制台会报警告
-
-How-
// 子组件 import {useRef,forwardRef} from 'react' const ComChild = forwardRef((props, ref) => { return ( <div> <input type="text" defaultValue={props.value} ref={ref} /> <button onClick={() => console.log(ref.current)}>点击打印ref</button> </div> ) }) // 父组件 const myComponent = () => { const childRef = useRef() return ( <ComChild ref={childRef} value='这是子组件的value值' /> ) }
-
-
UseImperativeHandle
-
-What-
- 该 Hook 一般配合 React.forwardRef 使用,主要用于在父组件中可以使用 ref 获取子组件暴露出来的属性和方法
-
-Why-
- 用于自定义暴露给父组件的 ref 对象。它允许在函数组件中控制 ref 的内容,而不仅仅是将 ref 直接指向 DOM 元素或组件实例
-
好处
- 封装内部实现:通过 useImperativeHandle,可以控制哪些方法和属性暴露给父组件,从而封装组件的内部实现细节,提供更清晰可控的接口
- 提高代码的可维护性:通过限制暴露的接口,可以更容易地维护和修改组件的内部实现,而不影响依赖该数组的父组件
- 增强组件的复用性:可以定义一组特定的方法和属性,使得组件在不同的上下文种更容易复用,而不用暴露所有的内部细节
-
总结
-
useImperativeHandle 可以在函数组件中自定义暴露给父组件的 ref 对象,从而更好地封装组件的内部实现,提高组件的可复用性和可维护性。
-
-
-How-
- 配合 React.forwardRef 的使用方法
// 子组件 import { forwardRef, useImperativeHandle } from "react"; const ComChild1 = forwardRef<{ handleFunction: () => void, test?: string }, { name: string }>((props, ChildRef) => { useImperativeHandle(ChildRef, () => ({ handleFunction, test: '子节点的文本' })); const handleFunction = () => { console.log('父组件点击'); } return <div>子组件1 name:{props.name}</div>; }) export default ComChild1 // 父组件 import { useEffect, useRef, useState } from "react"; import ComChild1 from "./components/HOC/ComChild1"; export default function App() { const [show1, setShow1] = useState(true) const ChildRef = useRef<{ handleFunction: () => void, text?: string }>(null) const toggleOnOff = () => { setShow1(!show1) ChildRef.current?.handleFunction() } useEffect(() => { console.log(ChildRef.current, '******'); }, []) return ( <div> <button onClick={toggleOnOff}>toggle</button> <ComChild1 name='demo' ref={ChildRef} /> </div> ); } - 不配合 React.forwardRef 的写法
// 父组件 // 定义 ref const orderRef = useRef<{ open: (type: IAction, data?: Order.OrderItem) => void }>() // 使用子组件的方法 const handleAddOrder = () => { orderRef.current?.open('create') } // 引入子组件 <CreateOrder mRef={orderRef} /> // 子组件 // 定义 ref类型 包含一个 open 方法 接收两个参数 export interface IModalProp<T> { mRef: MutableRefObject<{ open: (type: IAction, data: T) => void } | undefined> update: () => void } const CreateOrder = (props: IModalProp<Order.OrderItem>) => { // 传递给父组件 这个open 方法 useImperativeHandle(props.mRef, () => { return { open } }) // 定义 open 方法 const open = (type: IAction, data?: Order.OrderItem) => { setAction(type) } -----
- 配合 React.forwardRef 的使用方法
-


被折叠的 条评论
为什么被折叠?



