5

我试图在我的 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;
4

1 回答 1

3

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

function App() {
  const searchInputRef = useRef(null);
  return (
    <>
      <Header searchInputRef={searchInputRef} />
      <ResultsList searchInputRef={searchInputRef} />
    </>
  );
}

附加并使用您已经在其中的 refHeader

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>
  );
}

同样,您也可以searchInputRefResultsList组件中访问。

function ResultsList({ searchInputRef }) {

  ...

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

编辑

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

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

创建和导出上下文。

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>
}

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

于 2020-12-02T22:00:54.367 回答