首页 > 解决方案 > 使用 React State 和 UseEffect 控制输入字段焦点

问题描述

我有一个非常基本的表单,我试图使用 state 和 useEffect 控制输入元素的焦点和模糊。通过鼠标选择和取消选择输入效果很好,但我还有一个按钮可以打开/关闭无法正常工作的焦点。当您按下按钮时,焦点永远不会由于某种原因而关闭。

我必须在这里遗漏一些简单的东西,但这让我发疯。这是下面的代码,以及一个工作 codepen 的链接

const Focus = () => {
  const [focused, setFocused] = useState(true)
  const inputRef = useRef()

  useEffect(() => {
    if (focused) {
      inputRef.current.focus()
    } else {
      inputRef.current.blur()
    }
  }, [focused])

  return (
    <div>
      <input
        ref={inputRef}
        type="text"
        onBlur={() => setFocused(false)}
        onFocus={() => setFocused(true)}
      />
      <button onClick={() => setFocused(!focused)}>Toggle Focus</button>
    </div>
  )
}

标签: javascriptreactjsreact-hooks

解决方案


评论 onBlurHandler 解决了这个问题

 // onBlur={() => setFocused(false)}

当您调用 setFocused(!focused) 时,将触发 useEffect 进而触发 onBlur 并不必要地尝试再次调用 setFocus。这会产生某种无限循环。因此,只需从输入中删除不必要的 onBlur,因为它没有任何用途

const Focus = () => {
  const [focused, setFocused] = React.useState(true);
  const inputRef = React.useRef();


  React.useEffect(() => {
    console.log('current ' , focused)
    if (focused) {
      inputRef.current.focus();
    } else {
      inputRef.current.blur();
    }
  }, [focused]);
  
  const toggleFocus = () => {
    setFocused(prev => !prev)
  }
  
  const unFocus = () => {
    setTimeout(() => {
            if (focused) setFocused(false)
        }, 300);
  }
  
  const focus =() => {
    if(!focused)setFocused(true)
  }

  return (
    <div>
      <input
        ref={inputRef}
        type="text"
        onBlur={unFocus}
        onFocus={focus}
      />
      <button onClick={toggleFocus}>Toggle Focus</button>
    </div>
  );
};

ReactDOM.render(<Focus />, document.querySelector('.app'))

下面的代码解决了这个问题。我不确定确切的问题是什么,但很可能是由 react 内部处理的竞争条件


推荐阅读