React中useRef的ref.current作为Prop/Context传递时始终为undefined
解决React组件间通过Ref更新元素类名的问题
问题场景
想要在SearchBar组件触发事件时,更新Header组件中某个元素的类名。尝试将Header中创建的useRef实例通过props和Context两种方式传递给SearchBar,但两种方式下console.log(ref.current)都返回undefined。
问题原因分析
- Props传递错误:
SearchBar组件的参数写法错误,直接接收logo会把整个props对象赋值给logo,而非传入的ref实例,导致logo.current取不到DOM元素。 - 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
相关产品推荐
相关产品推荐

