如何将 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