如何将 ref 传递给相邻组件
How do I pass ref to a neighbour component
我正在尝试在我的 Header 组件中的搜索输入上使用 ref,这不是我的 ResultsList 组件的高阶组件。我想将焦点放在 ResultsList 组件的页眉搜索输入上。从 Header 看很直观,因为我所要做的就是下面的内容。如果我想在 ResultsList 中创建一个按钮,该按钮将专注于 Header 中的输入元素怎么办?我如何通过此参考?我已经阅读了有关 forwardRef 的内容,但我没有传递我的 ref 转发。 ResultsList 不是 Header 的子项。
import React, { useState, useRef } from 'react';
import { useHistory } from 'react-router-dom';
const Header = () => {
const searchInput = useRef(null);
const history = useHistory();
const [searchValue, setSearchValue] = useState(keyword);
function handleChange(event) {
setSearchValue(event.target.value);
}
function handleSearch(event) {
event.preventDefault();
if(searchValue) {
history.push(`/search/${searchValue}`);
} else {
searchInput.current.focus();
}
}
return (
<form onSubmit={handleSearch} role="search">
<input
value={searchValue}
onChange={handleChange}
className="HeaderSearch__input"
id="header-search-input"
placeholder="Search a repository"
ref={searchInput}>
</input>
</form>
);
}
export default Header;
我的 App 组件是这样的
import React from 'react';
import Header from './Header';
import ResultsList from './ResultsList';
function App() {
return (
<>
<Header />
<ResultsList />
</>
);
}
export default App;
您将需要使用“提升状态”模式。在 App
中声明 react ref 并将其传递给两个组件,传递给 Header
以将 ref 附加到节点,传递给 ResultsList
以访问 ref 并设置“焦点”。
function App() {
const searchInputRef = useRef(null);
return (
<>
<Header searchInputRef={searchInputRef} />
<ResultsList searchInputRef={searchInputRef} />
</>
);
}
像在 Header
中一样附加并使用 ref
const Header = ({ searchInputRef }) => {
const history = useHistory();
const [searchValue, setSearchValue] = useState(keyword);
function handleChange(event) {
setSearchValue(event.target.value);
}
function handleSearch(event) {
event.preventDefault();
if(searchValue) {
history.push(`/search/${searchValue}`);
} else {
searchInputRef.current.focus();
}
}
return (
<form onSubmit={handleSearch} role="search">
<input
value={searchValue}
onChange={handleChange}
className="HeaderSearch__input"
id="header-search-input"
placeholder="Search a repository"
ref={searchInputRef}>
</input>
</form>
);
}
同样,您也可以在 ResultsList
组件中访问 searchInputRef
。
function ResultsList({ searchInputRef }) {
...
<button
type="button"
onClick={() => searchInputRef.current?.focus()}
>
Set Search Focus
</button>
}
编辑
What if more deeply nested components need ref?
如果子组件 不是 直接后代,那么您可以利用反应上下文来允许子组件访问 ref,而无需将其作为 prop 通过 React 树传递。
创建并导出上下文。
const SearchInputRefContext = React.createContext(null);
为 App
中的儿童提供上下文
import SearchInputRefContext from '.....';
function App() {
const searchInputRef = useRef(null);
return (
<SearchInputRefContext.Provider value={searchInputRef}>
<Header />
<ResultsList />
</SearchInputRefContext.Provider>
);
}
访问任何子子组件中的上下文
const Header = () => {
const history = useHistory();
const searchInputRef = useContext(SearchInputRefContext);
const [searchValue, setSearchValue] = useState(keyword);
function handleChange(event) {
setSearchValue(event.target.value);
}
function handleSearch(event) {
event.preventDefault();
if(searchValue) {
history.push(`/search/${searchValue}`);
} else {
searchInputRef.current.focus();
}
}
return (
<form onSubmit={handleSearch} role="search">
<input
value={searchValue}
onChange={handleChange}
className="HeaderSearch__input"
id="header-search-input"
placeholder="Search a repository"
ref={searchInputRef}>
</input>
</form>
);
}
无论嵌套多深
function ReallyDeepComponent() {
const searchInputRef = useContext(SearchInputRefContext);
...
<button
type="button"
onClick={() => searchInputRef.current?.focus()}
>
Set Search Focus
</button>
}
如果您碰巧仍在使用基于 class 的组件,请参阅此 section。
我正在尝试在我的 Header 组件中的搜索输入上使用 ref,这不是我的 ResultsList 组件的高阶组件。我想将焦点放在 ResultsList 组件的页眉搜索输入上。从 Header 看很直观,因为我所要做的就是下面的内容。如果我想在 ResultsList 中创建一个按钮,该按钮将专注于 Header 中的输入元素怎么办?我如何通过此参考?我已经阅读了有关 forwardRef 的内容,但我没有传递我的 ref 转发。 ResultsList 不是 Header 的子项。
import React, { useState, useRef } from 'react';
import { useHistory } from 'react-router-dom';
const Header = () => {
const searchInput = useRef(null);
const history = useHistory();
const [searchValue, setSearchValue] = useState(keyword);
function handleChange(event) {
setSearchValue(event.target.value);
}
function handleSearch(event) {
event.preventDefault();
if(searchValue) {
history.push(`/search/${searchValue}`);
} else {
searchInput.current.focus();
}
}
return (
<form onSubmit={handleSearch} role="search">
<input
value={searchValue}
onChange={handleChange}
className="HeaderSearch__input"
id="header-search-input"
placeholder="Search a repository"
ref={searchInput}>
</input>
</form>
);
}
export default Header;
我的 App 组件是这样的
import React from 'react';
import Header from './Header';
import ResultsList from './ResultsList';
function App() {
return (
<>
<Header />
<ResultsList />
</>
);
}
export default App;
您将需要使用“提升状态”模式。在 App
中声明 react ref 并将其传递给两个组件,传递给 Header
以将 ref 附加到节点,传递给 ResultsList
以访问 ref 并设置“焦点”。
function App() {
const searchInputRef = useRef(null);
return (
<>
<Header searchInputRef={searchInputRef} />
<ResultsList searchInputRef={searchInputRef} />
</>
);
}
像在 Header
const Header = ({ searchInputRef }) => {
const history = useHistory();
const [searchValue, setSearchValue] = useState(keyword);
function handleChange(event) {
setSearchValue(event.target.value);
}
function handleSearch(event) {
event.preventDefault();
if(searchValue) {
history.push(`/search/${searchValue}`);
} else {
searchInputRef.current.focus();
}
}
return (
<form onSubmit={handleSearch} role="search">
<input
value={searchValue}
onChange={handleChange}
className="HeaderSearch__input"
id="header-search-input"
placeholder="Search a repository"
ref={searchInputRef}>
</input>
</form>
);
}
同样,您也可以在 ResultsList
组件中访问 searchInputRef
。
function ResultsList({ searchInputRef }) {
...
<button
type="button"
onClick={() => searchInputRef.current?.focus()}
>
Set Search Focus
</button>
}
编辑
What if more deeply nested components need ref?
如果子组件 不是 直接后代,那么您可以利用反应上下文来允许子组件访问 ref,而无需将其作为 prop 通过 React 树传递。
创建并导出上下文。
const SearchInputRefContext = React.createContext(null);
为 App
import SearchInputRefContext from '.....';
function App() {
const searchInputRef = useRef(null);
return (
<SearchInputRefContext.Provider value={searchInputRef}>
<Header />
<ResultsList />
</SearchInputRefContext.Provider>
);
}
访问任何子子组件中的上下文
const Header = () => {
const history = useHistory();
const searchInputRef = useContext(SearchInputRefContext);
const [searchValue, setSearchValue] = useState(keyword);
function handleChange(event) {
setSearchValue(event.target.value);
}
function handleSearch(event) {
event.preventDefault();
if(searchValue) {
history.push(`/search/${searchValue}`);
} else {
searchInputRef.current.focus();
}
}
return (
<form onSubmit={handleSearch} role="search">
<input
value={searchValue}
onChange={handleChange}
className="HeaderSearch__input"
id="header-search-input"
placeholder="Search a repository"
ref={searchInputRef}>
</input>
</form>
);
}
无论嵌套多深
function ReallyDeepComponent() {
const searchInputRef = useContext(SearchInputRefContext);
...
<button
type="button"
onClick={() => searchInputRef.current?.focus()}
>
Set Search Focus
</button>
}
如果您碰巧仍在使用基于 class 的组件,请参阅此 section。