当聚焦单选按钮时,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
我在这里整理了一个小演示: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