如何将 ref 传递给相邻组件

Laz*_*zyk 7 reactjs react-hooks use-ref

我试图在我的 Header 组件中的搜索输入上使用 ref ,它不是我的 ResultsList 组件的高阶组件。我想将焦点集中在 ResultsList 组件的标题搜索输入上。从标题来看它很直观,因为我所要做的就是下面的内容。如果我想在 ResultsList 中创建一个专注于 Header 中的输入元素的按钮该怎么办?我如何通过这个参考?我已经阅读过有关forwardRef的内容,但我没有将我的参考转发。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;
Run Code Online (Sandbox Code Playgroud)

我的应用程序组件看起来像这样

import React from 'react';
import Header from './Header';
import ResultsList from './ResultsList';

function App() {
  return (
    <>
      <Header />
      <ResultsList />
    </>
  );
}

export default App;
Run Code Online (Sandbox Code Playgroud)

Dre*_*ese 6

您将需要利用“提升状态”模式。声明react ref并将App其传递给两个组件,toHeader将ref附加到节点,toResultsList访问ref并设置“焦点”。

function App() {
  const searchInputRef = useRef(null);
  return (
    <>
      <Header searchInputRef={searchInputRef} />
      <ResultsList searchInputRef={searchInputRef} />
    </>
  );
}
Run Code Online (Sandbox Code Playgroud)

附加并使用您已经在的引用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>
  );
}
Run Code Online (Sandbox Code Playgroud)

同样,您也可以在组件searchInputRef中访问。ResultsList

function ResultsList({ searchInputRef }) {

  ...

  <button
    type="button"
    onClick={() => searchInputRef.current?.focus()}
  >
    Set Search Focus
  </button>
}
Run Code Online (Sandbox Code Playgroud)

编辑

如果嵌套更深的组件需要引用怎么办?

如果子组件不是直接后代,那么您可以利用 React 上下文来允许子组件访问 ref,而无需将其作为 prop 通过 React 树传递。

创建并导出上下文。

const SearchInputRefContext = React.createContext(null);
Run Code Online (Sandbox Code Playgroud)

为儿童提供背景App

import SearchInputRefContext from '.....';

function App() {
  const searchInputRef = useRef(null);
  return (
    <SearchInputRefContext.Provider value={searchInputRef}>
      <Header />
      <ResultsList />
    </SearchInputRefContext.Provider>
  );
}
Run Code Online (Sandbox Code Playgroud)

访问任何子子组件中的上下文

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>
  );
}
Run Code Online (Sandbox Code Playgroud)

无论嵌套多深

function ReallyDeepComponent() {
  const searchInputRef = useContext(SearchInputRefContext);

  ...

  <button
    type="button"
    onClick={() => searchInputRef.current?.focus()}
  >
    Set Search Focus
  </button>
}
Run Code Online (Sandbox Code Playgroud)

如果您碰巧仍在使用基于类的组件,请参阅本节。

  • @LazioTibijczyk [可选链接运算符](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining)。它基本上是一个空检查,因此 `searchInputRef.current?.focus()` 相当于 `searchInputRef.current &amp;&amp; searchInputRef.current.focus()`。 (2认同)