在 React.js 中使用 refs

2025-06-04

在 React.js 中使用 refs

在本文中,我们将探讨为什么 React.js 这个让你的代码远离 DOM 操作的库,会为你敞开大门。React 会根据组件的状态重新思考视图。它提供了 JSX(一种 JavaScript 上的语法糖)来设计视图层,然后修改 DOM 本身,而不是将控制权交给开发人员。

尽管如此,React 团队还是提供了逃生路线,并使库保持开放,以应对超出 React 设计范围的某些情况。

创建 refs

Refs 是逃生路线,最好尽可能避免使用它们。当我们使用 ref 获取 DOM 元素,然后修改其属性时,可能会与 React 的 diff 和 update 方法发生冲突。

让我们从一个简单的组件开始,并使用 ref 获取一个 DOM 元素,假设您已经知道如何设置一个基本的 react 应用程序。

import React, { useRef } from 'react'

function Button ({ label, action }) {
        // declare & initializing a reference to null
   const buttonRef = useRef(null)

   // attaching 'buttonRef' to the <button> element in JSX
    return (
      <button onClick={action} ref={buttonRef}>{label}</button>
    )
  }
}
Enter fullscreen mode Exit fullscreen mode

在上面的代码中,我们使用 React Hook 'useRef' 来创建并初始化一个名为 buttonRef 的变量。然后,我们将 buttonRef 赋值给 button JSX 元素上的 ref 属性。

使用 React refs

正如我们前面所讨论的,我们基于状态声明视图,虽然我们仍然使用函数来修改状态,但我们无法直接控制 DOM 的变化。不过,在某些情况下,在代码中引入 ref 是有意义的。

焦点控制

为了更好地理解问题陈述,让我们将情况描述成故事。

Arjun 是 Doogle 公司的软件开发实习生,他的经理给他布置了创建联系表单的任务。经理要求他在打开模态框时,重点关注表单中的第一个输入元素。Arjun 不知道如何在 React.js 中实现这一点。让我们来帮帮 Arjun。

import React, { useState } from "react";

const InputModal = ({ close }) => {
  const [value, updateVal] = useState("");
  const onChange = (e) => {
    updateVal(e.target.value);
  };

  const onSubmit = (e) => {
    e.preventDefault();
    close();
  };

  return (
    <div className="overlay">
      <div className="modal">
        <h1>Insert a new value</h1>
        <form action="?" onSubmit={onSubmit}>
          <input type="text" onChange={onChange} value={value} />
          <button>Save new value</button>
        </form>
      </div>
    </div>
  );
};

export default InputModal;
Enter fullscreen mode Exit fullscreen mode

我们需要做的第一件事是获取对输入的引用。

import React, { useState, useRef } from "react";

const InputModal = ({ close }) => {
  const [value, updateVal] = useState("");
  const inputRef = useRef(null);

  const onChange = (e) => {
    updateVal(e.target.value);
  };

  const onSubmit = (e) => {
    e.preventDefault();
    close();
  };

  return (
    <div className="overlay">
      <div className="modal">
        <h1>Insert a value</h1>
        <form action="?" onSubmit={onSubmit}>
          <input type="text" onChange={onChange} value={value} ref={inputRef} />
          <button>Save</button>
        </form>
      </div>
    </div>
  );
};

export default InputModal;
Enter fullscreen mode Exit fullscreen mode

接下来,当我们的模式加载时,我们强制调用输入参考上的焦点。

import React, { useState, useRef, useEffect } from "react";

const InputModal = ({ close }) => {
  const [value, updateVal] = useState("");
  const inputRef = useRef(null);

  useEffect(() => {
    inputRef.current.focus();
  }, []);

  const onChange = (e) => {
    updateVal(e.target.value);
  };

  const onSubmit = (e) => {
    e.preventDefault();
    close();
  };

  return (
    <div className="overlay">
      <div className="modal">
        <h1>Insert a value</h1>
        <form action="?" onSubmit={onSubmit}>
          <input type="text" onChange={onChange} value={value} ref={inputRef} />
          <button>Save</button>
        </form>
      </div>
    </div>
  );
};

export default InputModal;
Enter fullscreen mode Exit fullscreen mode

注意:您需要通过声明的 ref 的当前属性来访问该元素。

点击此链接查看代码。尝试注释掉 inputRef 的实现,看看输入焦点在有 ref 和无 ref 的情况下是如何变化的。

检测是否包含元素

类似地,我们希望在事件触发时在应用中执行某个操作。比如,当用户点击模态框外部时关闭模态框。

import React, { useState, useRef, useEffect } from "react";

const InputModal = ({ close }) => {
  const [value, updateVal] = useState("");
  const inputRef = useRef(null);
  const modalRef = useRef(null);

  const onClickOverlay = (e) => {
    const overlay = e.target;
    if (modalRef.current && !modalRef.current.contains(overlay)) {
      e.preventDefault();
      e.stopPropagation();
      close();
    }
  };
  useEffect(() => {
    inputRef.current.focus();
    document.body.addEventListener("click", onClickOverlay);
  }, []);

  const onChange = (e) => {
    updateVal(e.target.value);
  };

  const onSubmit = (e) => {
    e.preventDefault();
    close();
  };

  return (
    <div className="overlay">
      <div className="modal" ref={modalRef}>
        <h1>Insert a value</h1>
        <form action="?" onSubmit={onSubmit}>
          <input type="text" onChange={onChange} value={value} ref={inputRef} />
          <button>Save</button>
        </form>
      </div>
    </div>
  );
};

export default InputModal;
Enter fullscreen mode Exit fullscreen mode

这里,我们检查用户点击是否超出了模态框引用限制。如果超出,我们将从 props 中调用 close() 函数来关闭模态框。

集成基于 DOM 的库

与 React 类似,在其生态系统之外,也有一些已使用多年的实用程序和库。要使用这些库,ref 就派上用场了。

GreenSock 库是动画示例的热门选择。要使用它,我们需要将 DOM 元素传递给它的任意方法。

让我们回到我们的模态框并添加一些动画

import React, { useState, useRef, useEffect } from "react";
import gsap from "gsap";

const InputModal = ({ close }) => {
  const [value, updateVal] = useState("");

  const inputRef = useRef(null);
  const modalRef = useRef(null);
  const overlayRef = useRef(null);

  const onComplete = () => {
    inputRef.current.focus();
  };
  const gaspTimeline = gsap.timeline({ paused: true, onComplete });

  const onClickOverlay = (e) => {
    const overlay = e.target;
    if (modalRef.current && !modalRef.current.contains(overlay)) {
      e.preventDefault();
      e.stopPropagation();
      close();
    }
  };
  useEffect(() => {
    //timeline - gasp
    gaspTimeline
      .from(overlayRef.current, {
        duration: 0.25,
        autoAlpha: 0
      })
      .from(modalRef.current, {
        duration: 0.25,
        autoAlpha: 0,
        y: 25
      });

    gaspTimeline.play();

    document.body.addEventListener("click", onClickOverlay);
  }, []);

  const onChange = (e) => {
    updateVal(e.target.value);
  };

  const onSubmit = (e) => {
    e.preventDefault();
    close();
  };

  return (
    <div className="overlay" ref={overlayRef}>
      <div className="modal" ref={modalRef}>
        <h1>Insert a value</h1>
        <form action="?" onSubmit={onSubmit}>
          <input type="text" onChange={onChange} value={value} ref={inputRef} />
          <button>Save</button>
        </form>
      </div>
    </div>
  );
};

export default InputModal;
Enter fullscreen mode Exit fullscreen mode

**这是工作演示。 **

转发 Refs

Refs 对于特定操作非常有用。这里展示的示例比我们通常在实际 Web 应用程序中看到的要简单一些。我们需要处理复杂的组件,并且很少直接使用纯 HTML 元素。在一个组件中使用另一个组件的 ref 是很常见的。

import React from 'react'

const LabelledInput = (props) => {
  const { id, label, value, onChange } = props

  return (
    <div class="labelled--input">
      <label for={id}>{label}</label>
      <input id={id} onChange={onChange} value={value} />
    </div>
  )
}

export default LabelledInput
Enter fullscreen mode Exit fullscreen mode

现在的问题是,将 ref 传递给该组件将返回其实例,即 React 组件引用,而不是像我们在第一个示例中那样我们想要关注的输入元素。

React 提供了forwardRef,它允许您在内部定义 ref 将指向哪个元素。

import React from 'react'

const LabelledInput = (props, ref) => {
  const { id, label, value, onChange } = props

  return (
    <div class="labelled--input">
      <label for={id}>{label}</label>
      <input id={id} onChange={onChange} value={value} ref={ref}/>
    </div>
  )
}

export default React.forwardRef(LabelledInput)
Enter fullscreen mode Exit fullscreen mode

现在,当父组件传递 ref 值时,它将获取输入,这有助于避免暴露组件的内部和属性并破坏其封装。

最初发布于amodshinde.com

文章来源:https://dev.to/amoled27/using-refs-in-reactjs-4oog
PREV
介绍 Reactive Resume v2!
NEXT
出色的渗透测试 出色的渗透测试