Reactjs 如何将ref传递给相邻组件

Reactjs 如何将ref传递给相邻组件,reactjs,use-ref,Reactjs,Use Ref,我试图在我的标题组件中的搜索输入上使用ref,它不是我的ResultsList组件的高阶组件。我想从ResultsList组件将焦点设置在标题的搜索输入上。这是直观的从标题,因为我所要做的是下面。如果我想在ResultsList中创建一个按钮,该按钮将集中在标题中的输入元素上,该怎么办?我怎么通过这个裁判?我已经阅读了forwardRef,但我不会将我的ref转发。ResultsList不是标头的子级 import React,{useState,useRef}来自“React”; 从'rea

我试图在我的标题组件中的搜索输入上使用ref,它不是我的ResultsList组件的高阶组件。我想从ResultsList组件将焦点设置在标题的搜索输入上。这是直观的从标题,因为我所要做的是下面。如果我想在ResultsList中创建一个按钮,该按钮将集中在标题中的输入元素上,该怎么办?我怎么通过这个裁判?我已经阅读了forwardRef,但我不会将我的ref转发。ResultsList不是标头的子级

import React,{useState,useRef}来自“React”;
从'react router dom'导入{useHistory};
常量头=()=>{
const searchInput=useRef(null);
const history=useHistory();
const[searchValue,setSearchValue]=useState(关键字);
函数句柄更改(事件){
setSearchValue(事件目标值);
}
函数handleSearch(事件){
event.preventDefault();
如果(搜索值){
history.push(`/search/${searchValue}`);
}否则{
searchInput.current.focus();
}
}
返回(
);
}

导出默认标题您需要使用“提升状态提升”模式。在
App
中声明react ref,并将其传递给两个组件,传递到
标题
将ref附加到节点,传递到
结果列表
访问ref并设置“焦点”

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

function ResultsList({ searchInputRef }) {

  ...

  <button
    type="button"
    onClick={() => searchInputRef.current?.focus()}
  >
    Set Search Focus
  </button>
}
应用程序中的儿童提供上下文

import SearchInputRefContext from '.....';

function App() {
  const searchInputRef = useRef(null);
  return (
    <SearchInputRefContext.Provider value={searchInputRef}>
      <Header />
      <ResultsList />
    </SearchInputRefContext.Provider>
  );
}
从“…”导入SearchInputRefContext;
函数App(){
const searchInputRef=useRef(null);
返回(
);
}
访问任何子组件中的上下文

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>
  );
}
const头=()=>{
const history=useHistory();
const searchInputRef=useContext(SearchInputRefContext);
const[searchValue,setSearchValue]=useState(关键字);
函数句柄更改(事件){
setSearchValue(事件目标值);
}
函数handleSearch(事件){
event.preventDefault();
如果(搜索值){
history.push(`/search/${searchValue}`);
}否则{
searchInputRef.current.focus();
}
}
返回(
);
}
不管嵌套有多深

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

  ...

  <button
    type="button"
    onClick={() => searchInputRef.current?.focus()}
  >
    Set Search Focus
  </button>
}
函数reallydepcomponent(){
const searchInputRef=useContext(SearchInputRefContext);
...
searchInputRef.current?.focus()}
>
设置搜索焦点
}

如果您仍在使用基于类的组件,请查看此信息。

查看
forwardRef
:@SakoBu我在说明中提到过,但我添加按钮的结果列表不是标题的子项。如果我没有弄错,您可以使用React上下文进行操作。请看以下内容
ForwardRef
也可以工作,但您需要将其传递给这两个组件-请参阅演示。我更喜欢使用上下文,但两者都可以。是的,我想到了,但是如果我的ResultsList在层次结构中嵌入得更深,比如ResultsPage>ResultsList呢?我要把它传给道具两次吗?这是一种常见的做法吗?@laziotibjczyk将道具向下传递一级是很常见的,下一级或更高的道具可能不太常见。这种模式被称为“道具钻孔”,在这里你可以将道具穿过许多层。react提供的解决方案是“提供了一种通过组件树传递数据的方法,而无需在每个级别手动传递道具。”您可以创建一个上下文,提供共享引用和组件,只要它们位于提供程序的子树中,可以访问上下文值。@laziotibjczyk如果有兴趣,我可以更新我的答案,并尝试提供更多详细信息。@laziotibjczyk当然可以。我不觉得这不合理,因为它解决了“支柱钻井”的问题。我想您会发现代码非常简洁明了。@laziotibjczyk。它基本上是一个空检查,因此
searchInputRef.current?.focus()
相当于
searchInputRef.current&&searchInputRef.current.focus()
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>
}