useRef钩子大法好!

在React.js中,useRef是一个钩子,允许你创建一个对元素或值的可变引用。与useState钩子不同,更新useRef不会触发组件的重新渲染。它通常用于直接访问和管理DOM元素,存储持久值,或处理不应触发重新渲染的值。

useRef的基本语法如下:

const refContainer = useRef(initialValue);

useRef的主要用途

1. 访问DOM元素

useRef的一个最常见的用例是访问DOM元素。你可以使用useRef直接引用组件内的元素,而不是使用document.getElementById或其他DOM查询。

import React, { useRef } from 'react';

const ExampleComponent = () => {
  const inputRef = useRef(null);

  const handleClick = () => {
    // 点击按钮时,聚焦输入元素
    inputRef.current.focus();
  };

  return (
    
); };

2. 存储之前的值

你可以使用useRef存储一个跨渲染持久的值,但更新它不会触发重新渲染。当你需要跟踪之前的值而不触发不必要的渲染时,这可能非常有用。

import React, { useEffect, useRef } from 'react';

const PreviousValueComponent = ({ value }) => {
  const prevValueRef = useRef();

  useEffect(() => {
    prevValueRef.current = value;
  }, [value]);

  return (
    

Current Value: {value}

Previous Value: {prevValueRef.current}

); };

3. 使用外部库

有时候,当集成期望某些数据的可变引用的外部库时,useRef可能很有用。

import React, { useEffect, useRef } from 'react';
import externalLibrary from 'some-external-library';

const ExternalLibraryComponent = () => {
  const dataRef = useRef([]);

  useEffect(() => {
    // 更新外部库的最新数据
    externalLibrary.updateData(dataRef.current);
  }, []);

  // ... 组件的剩余部分
};

记住,由于useRef不会触发重新渲染,如果你需要更新组件并在UI中反映更改,你应该使用useState。只有当你需要管理一个不应影响组件渲染的可变值或引用时,才使用useRef

useImperativeHandle

useImperativeHandle是一个React钩子,允许你自定义暴露给父组件的实例值,当在子组件上使用ref时。它通常与forwardRefuseRef一起使用,为从其父组件与子组件的方法或属性进行交互提供了一个更加控制和明确的方式。

让我们创建一个使用useRefuseImperativeHandleforwardRef的例子,构建一个简单的自定义输入组件,该组件暴露一个方法来程序化地聚焦输入:

// 子组件 (CustomInput.js)

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

const CustomInput = forwardRef((props, ref) => {
  const inputRef = useRef(null);

  // 向父组件暴露'focusInput'方法
  useImperativeHandle(ref, () => ({
    focusInput: () => {
      inputRef.current.focus();
    }
  }));

  return (
    
  );
});

export default CustomInput;

在上面的子组件中,我们使用useRef创建了一个对输入元素的引用。然后,通过useImperativeHandle,我们通过ref向父组件暴露一个名为focusInput的方法。这使得父组件可以通过子组件的ref调用focusInput方法,并聚焦输入元素。

//父组件

import React, { useRef } from 'react';
import CustomInput from './CustomInput';

const ParentComponent = () => {
  const inputRef = useRef(null);

  const handleFocusButtonClick = () => {
    // 调用子组件的'focusInput'方法
    if (inputRef.current) {
      inputRef.current.focusInput();
    }
  };

  return (
    
{/* 带有ref的子组件 */}
); }; export default ParentComponent;

在父组件中,我们使用useRef创建一个引用(inputRef),用于与子组件的focusInput方法进行交互。当点击“Focus Input”按钮时,将执行handleFocusButtonClick函数。在此函数内部,我们调用子组件的ref上的focusInput方法,从而聚焦输入元素。

这个例子演示了如何将useRefuseImperativeHandle一起使用,以创建一种更加受控和明确的方式,从父组件与子组件的方法或属性进行交互。

更多示例

使用useRef更改元素的样式

import React, { useRef } from 'react';

const StyleChangeComponent = () => {
  const divRef = useRef(null);

  const handleColorChange = () => {
    divRef.current.style.backgroundColor = 'lightblue';
  };

  return (
    

This is a div element whose style can be changed.

); };

在这个例子中,我们使用useRef创建了一个名为divRef的引用,并将其附加到

元素。当点击“Change Color”按钮时,handleColorChange函数使用divRefcurrent属性直接访问并更改
元素的背景颜色。

使用useRef更改输入值

import React, { useRef } from 'react';

const InputChangeComponent = () => {
  const inputRef = useRef(null);

  const handleChangeValue = () => {
    inputRef.current.value = 'New Value';
  };

  return (
    
); };

在这个例子中,useRef用于创建一个名为inputRef的引用,并将其附加到元素。当点击“Change Input Value”按钮时,handleChangeValue函数访问inputRefcurrent属性以直接更改元素的值。

使用useRef和useImperativeHandle更改子组件中

元素的文本

// 子组件

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

const CustomHeader = forwardRef((props, ref) => {
  const headerRef = useRef(null);

  // 向父组件暴露'changeHeaderText'方法
  useImperativeHandle(ref, () => ({
    changeHeaderText: (text) => {
      headerRef.current.textContent = text;
    }
  }));

  return (
    

{props.text}

); }); export default CustomHeader;
// 父组件

import React, { useRef } from 'react';
import CustomHeader from './CustomHeader';

const ParentComponent = () => {
  const headerRef = useRef(null);

  const handleChangeTextButtonClick = () => {
    // 调用子组件的'changeHeaderText'方法
    if (headerRef.current) {
      headerRef.current.changeHeaderText('New Header Text');
    }
 };

  return (
    
{/* 带有ref的子组件 */}
); };

在这个例子中,子组件(CustomHeader.js)中使用了useRef钩子创建了一个名为headerRef的引用,并将其附加到

元素。useImperativeHandle钩子使我们能够通过ref向父组件暴露一个名为changeHeaderText的方法。然后,父组件(ParentComponent)可以使用这个方法来更改子组件中

元素的文本,而不会导致重新渲染。

结论

useRef是React.js中的一个强大的钩子,使开发人员能够有效地访问和修改DOM元素,保存值,并管理状态而不触发不必要的重新渲染。其多功能性使其成为开发人员工具箱中不可或缺的工具,允许在React应用程序中实现更强的控制和性能优化。通过掌握本文演示的使用案例和实际实现,开发人员可以充分利用useRef的潜力,构建更强大和高效的React组件。

你可能感兴趣的:(javascript,react.js,前端)