ref 在事件处理程序中没有值
ref doesn't have a value inside event handlers
目标功能:
当用户单击按钮时,将显示一个列表。当他在列表外单击时,它会关闭并且按钮应该获得焦点。 (遵循无障碍指南)
我试过的:
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}
/>
问题:
当我检查 hideList
函数的范围时,发现 ref
在除了单击事件处理程序内部的每个地方都获得了对按钮的正确引用,它是 {current: null}
.
控制台输出:Cannot read property 'focus' of null
示例:
https://codepen.io/moaaz_bs/pen/zQjoLK
- 单击按钮,然后单击外部并查看控制台。
创建您的参考
this.button = React.createRef();
将 Ref 添加到您的 DOM 元素
ref={this.button}
根据要求使用 Ref
this.button.current.focus();
使用 forwarding-refs
完成代码
const Button = React.forwardRef((props, ref) => {
return (
<button
onClick={props.toggleList}
ref={ref}
>
button
</button>
);
})
const List = (props) => {
const list = React.createRef();
handleClick = (e) => {
const clickIsOutsideList = !list.current.contains(e.target);
if (clickIsOutsideList) {
props.hideList();
}
}
React.useEffect(function addClickHandler() {
document.addEventListener('click', handleClick);
return function clearClickHandler() {
document.removeEventListener('click', handleClick);
}
}, []);
return (
<ul ref={list}>
<li>item</li>
<li>item</li>
<li>item</li>
</ul>
);
}
const button = React.createRef();
const App = () => {
const [ListHidden, setListHidden] = React.useState(true);
const toggleList = () => {
setListHidden(!ListHidden);
}
const hideList = () => {
setListHidden(true);
console.log(button)
button.current.focus();
}
return (
<div className="App">
<Button
toggleList={toggleList}
ref={button}
/>
{
!ListHidden &&
<List hideList={hideList} />
}
</div>
);
}
ReactDOM.render(<App />, document.getElementById('root'));
由于您已经在您的应用程序中使用挂钩,因此您唯一需要做的更改是使用 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'));
您需要它的原因是因为在您的功能组件的每次渲染中,如果您使用 React.createRef
将生成一个新的引用,而 useRef
的实现使得它生成一个ref 第一次调用时和 returns 以后任何时候的相同引用 re-renders.
P.S. A a thumb rule, you can say that useRef
should be used when you
want to have refs within functional components whereas createRef
should be used within class components.
目标功能:
当用户单击按钮时,将显示一个列表。当他在列表外单击时,它会关闭并且按钮应该获得焦点。 (遵循无障碍指南)
我试过的:
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}
/>
问题:
当我检查 hideList
函数的范围时,发现 ref
在除了单击事件处理程序内部的每个地方都获得了对按钮的正确引用,它是 {current: null}
.
控制台输出:Cannot read property 'focus' of null
示例:
https://codepen.io/moaaz_bs/pen/zQjoLK
- 单击按钮,然后单击外部并查看控制台。
创建您的参考
this.button = React.createRef();
将 Ref 添加到您的 DOM 元素
ref={this.button}
根据要求使用 Ref
this.button.current.focus();
使用 forwarding-refs
完成代码const Button = React.forwardRef((props, ref) => {
return (
<button
onClick={props.toggleList}
ref={ref}
>
button
</button>
);
})
const List = (props) => {
const list = React.createRef();
handleClick = (e) => {
const clickIsOutsideList = !list.current.contains(e.target);
if (clickIsOutsideList) {
props.hideList();
}
}
React.useEffect(function addClickHandler() {
document.addEventListener('click', handleClick);
return function clearClickHandler() {
document.removeEventListener('click', handleClick);
}
}, []);
return (
<ul ref={list}>
<li>item</li>
<li>item</li>
<li>item</li>
</ul>
);
}
const button = React.createRef();
const App = () => {
const [ListHidden, setListHidden] = React.useState(true);
const toggleList = () => {
setListHidden(!ListHidden);
}
const hideList = () => {
setListHidden(true);
console.log(button)
button.current.focus();
}
return (
<div className="App">
<Button
toggleList={toggleList}
ref={button}
/>
{
!ListHidden &&
<List hideList={hideList} />
}
</div>
);
}
ReactDOM.render(<App />, document.getElementById('root'));
由于您已经在您的应用程序中使用挂钩,因此您唯一需要做的更改是使用 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'));
您需要它的原因是因为在您的功能组件的每次渲染中,如果您使用 React.createRef
将生成一个新的引用,而 useRef
的实现使得它生成一个ref 第一次调用时和 returns 以后任何时候的相同引用 re-renders.
P.S. A a thumb rule, you can say that
useRef
should be used when you want to have refs within functional components whereascreateRef
should be used within class components.