You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中useRef的ref.current作为Prop/Context传递时始终为undefined

解决React组件间通过Ref更新元素类名的问题

问题场景

想要在SearchBar组件触发事件时,更新Header组件中某个元素的类名。尝试将Header中创建的useRef实例通过props和Context两种方式传递给SearchBar,但两种方式下console.log(ref.current)都返回undefined。

问题原因分析

  1. Props传递错误:SearchBar组件的参数写法错误,直接接收logo会把整个props对象赋值给logo,而非传入的ref实例,导致logo.current取不到DOM元素。
  2. Context传递逻辑错误:在Header中通过setRefState(logo.current)把DOM元素存在Context里,但在SearchBar中却尝试访问refState.current——实际上refState本身就是DOM元素,不需要再取.current。

修正方案

1. 修正SearchBar组件的props接收方式

组件的props是一个对象,需要解构出logo属性:

// 错误写法
const SearchBar = (logo) => { ... }

// 正确写法
const SearchBar = ({ logo }) => { ... }

2. 修正Context中ref的访问逻辑

建议将整个ref实例存入Context(而非DOM元素),这样后续操作更灵活:

  • 在Header的useEffect中传入logo而非logo.current
  • 在SearchBar中直接通过refState.current访问DOM元素

完整修正后的代码

Header组件:

import React, { useContext, useEffect, useRef } from "react";
import SearchContext from "../contexts/SearchStore";
import SearchBar from "./SearchBar";

const Header = () => {
  const { setRefState } = useContext(SearchContext);
  const logo = useRef();

  useEffect(() => {
    // 将ref实例存入Context,而非DOM元素
    setRefState(logo);
  }, [logo])

  return (
    <section id="headerContainer" className="d-grid">
      <h2
        ref={logo}
        className="ui header d-flex align-items-center justify-content-center mb-0 headerLogo"
      >
        <div className="content headerFont fs-3 ps-0">WhatSong.</div>
        <i className="play circle icon fs-5"></i>
      </h2>
      <div id="header2" className="d-flex align-items-center flex-row-reverse">
        <SearchBar logo={logo} />
      </div>
    </section>
  );
};

export default Header;

SearchBar组件:

import React, { useContext } from "react";
import SearchContext from "../contexts/SearchStore";
import "../styles/body.css";

// 解构props获取logo ref
const SearchBar = ({ logo }) => {
  const {
    term,
    setTerm,
    submittedTerm,
    setSubmittedTerm,
    refState,
  } = useContext(SearchContext);

  const styleLogo = () => {
    // 现在两种方式都能正确拿到DOM元素
    console.log(refState.current);
    console.log(logo.current);
    // 示例:添加/移除类名
    if (logo.current) {
      logo.current.classList.toggle("active-logo");
    }
  };
  
  return (
    <div id="searchContainer" className="w-50 d-flex justify-content-end">
      <form
        onSubmit={(e) => {
          e.preventDefault();
          setSubmittedTerm(term);
        }}
        className="ui left icon input w-50"
      >
        <i className="inverted circular search link icon"></i>
        <input
          value={term}
          type="text"
          placeholder="Search..."
          data-dashlane-rid="3640789f2356683f"
          data-form-type=""
          className="searchInput"
          onChange={({ target }) => setTerm(target.value)}
          onMouseEnter={styleLogo}
          onMouseLeave={styleLogo}
          onFocus={styleLogo}
          onBlur={styleLogo}
        />
      </form>
    </div>
  );
};

export default SearchBar;

额外注意点

  • 操作DOM元素前,先判断ref.current是否存在,避免空指针错误
  • 若只需要实现类名切换,也可以通过Context传递状态(比如isLogoActive),在Header中根据状态动态绑定类名,这种方式更符合React的状态驱动理念

内容的提问来源于stack exchange,提问作者userWantsToCode

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 05:15:33