当聚焦单选按钮时,React useRef / forwardRef 无法按预期工作

React useRef / forwardRef not working as expected when focusing a radio button

我在这里整理了一个小演示:https://codesandbox.io/s/bold-meitner-r3wzq?file=/src/App.js

当我单击按钮以显示并关注我的第一个单选按钮时 - 我的单选样式未应用。虽然,如果您紧接着按 space,它会聚焦正确的元素。

奇怪的是,如果我在 1 毫秒超时后聚焦,它会按预期工作。显然,这更像是一种破解而不是解决方案...

我觉得我在这里遗漏了一些非常简单的东西,任何帮助都会很棒!

谢谢!!

或者 - 这是复制所需的所有代码:

import React from "react";
import styled from "styled-components";
import "./styles.css";

const { useRef, forwardRef, useState } = React;

const Button = ({ onClick }) => (
  <button onClick={onClick}>Click me to show and focus radio buttons</button>
);

const Fieldset = styled.fieldset`
  display: ${props => (props.isVisible ? "block" : "none")};

  input {
    :focus {
      outline: 5px solid red;
    }
  }
`;

const RadioButtons = forwardRef(({ isVisible, legend }, ref) => (
  <Fieldset isVisible={isVisible}>
    <legend>{legend}</legend>
    <label for="one">One</label>
    <input ref={ref} type="radio" id="one" name="radios" />
    <label for="two">Two</label>
    <input type="radio" id="two" name="radios" />
  </Fieldset>
));

export default function App() {
  const [isVisible, setIsVisible] = useState(false);
  const inputRef = useRef();

  const focusInput = () => {
    setIsVisible(true);

    // This doesn't work as expected
    inputRef.current.focus();

    // This does - But it definitely doesn't feel like a "solution"
    // setTimeout(() => {
    //   inputRef.current.focus();
    // }, 1);
  };

  return (
    <>
      <Button onClick={focusInput} />
      <RadioButtons
        isVisible={isVisible}
        ref={inputRef}
        legend="Radio Legend"
      />
    </>
  );
}


因为它似乎总是......你觉得你用尽了所有的选择 - 然后你写了一个问题,然后你立即找到了答案!

在这种情况下 - 将 refs 焦点移动到一个 useEffect watches isVisible 就成功了

useEffect(() => {
    // I check here because my actual code toggles isVisible 
    if (isVisible) inputRef.current.focus();
}, [isVisible]);

仍然有兴趣看看这是否可以用更好的方式完成

您必须像这样将聚焦登录放在 useEffect 挂钩中

export default function App() {
  const [isVisible, setIsVisible] = useState(false);
  const inputRef = useRef();

  const focusInput = () => {
    setIsVisible(true);
  };

  React.useEffect(() => {
    if (isVisible) {
      inputRef.current.focus();
    }
  }, [isVisible]);

  return (
    <>
      <Button onClick={focusInput} />
      <RadioButtons
        isVisible={isVisible}
        ref={inputRef}
        legend="Radio Legend"
      />
    </>
  );
}

这是link