ref 在事件处理程序中没有值

Moa*_*nas 4 ref forward-reference reactjs

目标功能:
当用户单击按钮时,会显示一个列表。当他在列表外单击时,它会关闭并且按钮应该获得焦点。(遵循可访问性指南)

我试过的:

  const hideList = () => {
    // This closes the list
    setListHidden(true);
    // This takes a ref, which is forwarded to <Button/>, and focuses it
    button.current.focus();
  }

  <Button
    ref={button}
  />
Run Code Online (Sandbox Code Playgroud)

问题:
当我检查hideList函数的作用域时,发现ref除了在 click 事件处理程序内部之外的任何地方都获得了对按钮的正确引用,它是{current: null}.
控制台输出:Cannot read property 'focus' of null

示例
https : //codepen.io/moaaz_bs/pen/zQjoLK
- 单击按钮,然后单击外部并查看控制台。

Shu*_*tri 7

由于您已经在您的应用程序中使用钩子,您需要进行的唯一更改是使用useRef而不是createRef生成对列表的引用。

const Button = React.forwardRef((props, ref) => {
  return (
    <button 
      onClick={props.toggleList} 
      ref={ref}
    >
      button
    </button>
  );
})

const List = (props) => {
  const list = React.useRef();

  handleClick = (e) => {
    const clickIsOutsideList = !list.current.contains(e.target);
    console.log(list, clickIsOutsideList);
    if (clickIsOutsideList) {
      props.hideList();
    }
  }

  React.useEffect(function addClickHandler() {
    document.addEventListener('click', handleClick);
  }, []);

  return (
    <ul ref={list}>
      <li>item</li>
      <li>item</li>
      <li>item</li>
    </ul>
  );
}

const App = () => {
  const [ListHidden, setListHidden] = React.useState(true);

  const button = React.useRef();

  const toggleList = () => {
    setListHidden(!ListHidden);
  }

  const hideList = () => {
    setListHidden(true);
    button.current.focus();
  }

  return (
    <div className="App">
      <Button 
        toggleList={toggleList} 
        ref={button}
      />
      {
        !ListHidden &&
        <List hideList={hideList} />
      }
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById('root'));
Run Code Online (Sandbox Code Playgroud)

工作演示

你需要它的原因是因为在每一个渲染的功能组件,如果你使用,将产生一个新的参考React.createRef,而useRef实现这样就产生一个裁判时,其被称为第一次返回相同的参考随时在未来重新渲染。

PS一个经验法则,你可以说useRef当你想要在功能组件中使用引用时应该使用它,而createRef 应该在类组件中使用它。