英文:
How can ref.current never be null
问题
谢谢阅读。
我正在开发一个React应用程序。
使用“IntersectionObserver”观察多个“ref”。
代码中被注释掉的部分将为null。
知道为什么吗?
英文:
thank you for reading.
I am developing a React app.
Use "IntersectionObserver" to observe multiple "ref".
Commented out "*" parts in the code will be null.
Do you know why?
const refs = useRef<RefObject<HTMLVideoElement>[]>([]);
useEffect(() => {
const observer = new IntersectionObserver(entry => {
});
fetchData().then(results => {
// set data here
results.forEach((d, i) => refs.current[i] = createRef<HTMLVideoElement>());
refs.current.forEach(ref => {
console.log(ref.current); // *
if (ref.current) {
observer.observe(ref.current);
}
});
}).catch(error => {
alert("error");
});
return () => {
refs.current.forEach((ref) => {
if (ref.current) {
observer.unobserve(ref.current)
}
});
};
}, []);
By the way, "ref" instead of "ref.current" looks like the attached image.
答案1
得分: 1
以下是翻译好的部分:
原文:
Immediately after creating the refs, you try to use them, without ever assigning them to any element. Even if you do assign them to elements, the assignment would happen after you tried using them.
Instead use function refs to observe elements - the observer is stored in a ref. Whenever one of the observe
callbacks is called, it checks if observer.current
exists, and if not it initializes it. It then registers with the observer the element that used it as ref.
Don't bother cleaning individual observed elements, since the observer has weak links to the observed, so removing the elements won't cause a memory leak. Use a useEffect
to terminate the observer as a cleanup measure.
In addition, now you can add more items and pass them the ref callback (observer
).
翻译:
在创建引用后,立即尝试使用它们,而不将它们分配给任何元素。即使您将它们分配给元素,分配也会在尝试使用它们之后发生。
相反,使用函数引用来观察元素 - 观察器存储在引用中。每当调用observe
回调函数之一时,它都会检查observer.current
是否存在,如果不存在,则进行初始化。然后,它会向观察器注册使用它作为引用的元素。
不必担心清理单个观察的元素,因为观察器与观察的元素之间有弱引用,因此删除元素不会导致内存泄漏。使用useEffect
来终止观察器作为清理措施。
此外,现在您可以添加更多项目并将引用回调(observer
)传递给它们。
英文:
Immediately after creating the refs, you try to use them, without ever assigning them to any element. Even if you do assign them to elements, the assignment would happen after you tried using them.
Instead use function refs to observe elements - the observer is stored in a ref. Whenever one of the observe
callbacks is called, it checks if observer.current
exists, and if not it initializes it. It then registers with the observer the element that used it as ref.
Don't bother cleaning individual observed elements, since the observer has weak links to the observed, so removing the elements won't cause a memory leak. Use a useEffect
to terminate the observer as a cleanup measure.
In addition, now you can add more items and pass them the ref callback (observer
).
<!-- begin snippet: js hide: false console: true babel: true -->
<!-- language: lang-js -->
const { useRef, useCallback, useEffect } = React;
const Demo = () => {
const observer = useRef();
const observe = useCallback(el => {
if(!observer.current) { // init the observer if needed
observer.current = new IntersectionObserver(entry => {
console.log(entry);
});
}
observer.current.observe(el); // observe the element
}, []);
useEffect(() => () => { // cleanup
observer.current.disconnect();
}, []);
return (
<div>
<div ref={observe}>a</div>
<div ref={observe}>b</div>
<div ref={observe}>c</div>
</div>
);
};
ReactDOM
.createRoot(root)
.render(<Demo />);
<!-- language: lang-html -->
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="root"></div>
<!-- end snippet -->
You can extract this logic to a custom hook. The only change is to store the external callback function cb
in a ref
, so it won't be a dependency of the observe
function:
<!-- begin snippet: js hide: false console: true babel: true -->
<!-- language: lang-js -->
const { useRef, useCallback, useEffect } = React;
const useIntersection = cb => {
const observer = useRef();
const fn = useRef(cb);
useEffect(() => { // store the callback function in a ref
fn.current = cb;
});
useEffect(() => () => { // cleanup
observer.current.disconnect();
}, []);
return useCallback(el => {
if(!observer.current) { // init the observer if needed
observer.current = new IntersectionObserver(entry => {
fn.current(entry);
});
}
observer.current.observe(el); // observe the element
}, []);
};
const Demo = () => {
const observe = useIntersection(console.log);
return (
<div>
<div ref={observe}>a</div>
<div ref={observe}>b</div>
<div ref={observe}>c</div>
</div>
);
};
ReactDOM
.createRoot(root)
.render(<Demo />);
<!-- language: lang-html -->
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="root"></div>
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论