英文:
Costume Hook says array of elements is not iterable
问题
我正在尝试创建一个自定义钩子,用于调用IntersectionObserver
来观察ref
内的所有li
元素。
当我在组件中直接使用它时,它运行得很好:
const App = () => {
const array = [...Array(50).keys()];
const ref = React.useRef(null);
React.useEffect(() => {
const observer = new IntersectionObserver((entries) => {
entries.forEach((element) => {
if (element.isIntersecting) {
element.target.style.color = 'green';
}
});
});
ref.current.querySelectorAll(`li`).forEach((element) => {
observer.observe(element);
});
}, []);
return (
<ul ref={ref}>
{array.map((_, i) => <li key={i}>{i}</li>)}
</ul>
);
}
但当我将它分离到一个自定义钩子中时,它报错说它不可迭代:
const App = () => {
const array = [...Array(50).keys()];
const ref = React.useRef(null);
const useCustomHook = (elements) => {
React.useEffect(() => {
const observer = new IntersectionObserver((entries) => {
entries.forEach((element) => {
if (element.isIntersecting) {
element.target.style.color = 'green';
}
});
});
elements.forEach((element) => {
observer.observe(element);
});
}, []);
}
useCustomHook(ref?.current.querySelectorAll(`li`));
return (
<ul ref={ref}>
{array.map((_, i) => <li key={i}>{i}</li>)}
</ul>
);
}
是否有一种方式可以通过给自定义钩子一个元素数组来实现这一点?
谢谢! 😊
英文:
I am trying to create a costume hook that calls IntersectionObserver
for all of the li
elements inside a ref
.
When I just use it in the component, it works great:
<!-- begin snippet: js hide: false console: true babel: true -->
<!-- language: lang-js -->
const App = () => {
const array = [...Array(50).keys()];
const ref = React.useRef(null);
React.useEffect(() => {
const observer = new IntersectionObserver((entries) => {
entries.forEach((element: any) => {
if (element.isIntersecting) {
element.target.style.color = 'green';
}
})
})
ref.current.querySelectorAll(`li`).forEach(element => {
observer.observe(element);
});
}, [ ]);
return (
<ul ref={ref}>
{array.map((_, i) => <li key={i}>{i}</li>)}
</ul>
)
}
ReactDOM.createRoot(document.getElementById(`root`))
.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
<!-- language: lang-html -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js"></script><div id="root"></div>
<!-- end snippet -->
But When I separate it into a costume hook, it says it is not iterable:
<!-- begin snippet: js hide: false console: true babel: true -->
<!-- language: lang-js -->
const App = () => {
const array = [...Array(50).keys()];
const ref = React.useRef(null);
const useCostumeHook = (elements) => {
React.useEffect(() => {
const observer = new IntersectionObserver((entries) => {
entries.forEach((element: any) => {
if (element.isIntersecting) {
element.target.style.color = 'green';
}
})
})
elements.forEach(element => {
observer.observe(element);
});
}, [ ]);
}
useCostumeHook(ref?.current.querySelectorAll(`li`))
return (
<ul ref={ref}>
{array.map((_, i) => <li key={i}>{i}</li>)}
</ul>
)
}
ReactDOM.createRoot(document.getElementById(`root`))
.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
<!-- language: lang-html -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js"></script> <div id="root"></div>
<!-- end snippet -->
Is there a way to do this with just giving the costume hook an array of elements?
THANKS! 😊
答案1
得分: 0
当你调用这个钩子,并传递ref.current?.querySelectorAll(
li)
,ref.current
仍然是null
,所以结果是undefined
,无法迭代。
相反,传递一个函数,允许useEffect
块在ref
已经设置时获取项目:
const useCustomHook = (getElements) => {
React.useEffect(() => {
const observer = new IntersectionObserver((entries) => {
entries.forEach((element) => {
if (element.isIntersecting) {
element.target.style.color = 'green';
}
});
});
const elements = getElements();
elements?.forEach((element) => {
observer.observe(element);
});
}, []);
};
用法:
useCustomHook(() => ref.current?.querySelectorAll(`li`));
英文:
When you call the hook, and pass ref.current?.querySelectorAll(
li)
, the ref.current
is still null
, so the result is undefined
which not iterable.
Instead pass a function that would allow the useEffect
block to get the items when the ref
is already set:
const useCostumeHook = (getElements) => {
React.useEffect(() => {
const observer = new IntersectionObserver((entries) => {
entries.forEach((element: any) => {
if (element.isIntersecting) {
element.target.style.color = 'green';
}
})
})
const elements = getElements();
elements?.forEach(element => {
observer.observe(element);
});
}, []);
}
Usage:
useCostumeHook(() => ref.current?.querySelectorAll(`li`))
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论