Costume Hook says array of elements is not iterable

huangapple go评论84阅读模式
英文:

Costume Hook says array of elements is not iterable

问题

我正在尝试创建一个自定义钩子,用于调用IntersectionObserver来观察ref内的所有li元素。

当我在组件中直接使用它时,它运行得很好:

  1. const App = () => {
  2. const array = [...Array(50).keys()];
  3. const ref = React.useRef(null);
  4. React.useEffect(() => {
  5. const observer = new IntersectionObserver((entries) => {
  6. entries.forEach((element) => {
  7. if (element.isIntersecting) {
  8. element.target.style.color = 'green';
  9. }
  10. });
  11. });
  12. ref.current.querySelectorAll(`li`).forEach((element) => {
  13. observer.observe(element);
  14. });
  15. }, []);
  16. return (
  17. <ul ref={ref}>
  18. {array.map((_, i) => <li key={i}>{i}</li>)}
  19. </ul>
  20. );
  21. }

但当我将它分离到一个自定义钩子中时,它报错说它不可迭代:

  1. const App = () => {
  2. const array = [...Array(50).keys()];
  3. const ref = React.useRef(null);
  4. const useCustomHook = (elements) => {
  5. React.useEffect(() => {
  6. const observer = new IntersectionObserver((entries) => {
  7. entries.forEach((element) => {
  8. if (element.isIntersecting) {
  9. element.target.style.color = 'green';
  10. }
  11. });
  12. });
  13. elements.forEach((element) => {
  14. observer.observe(element);
  15. });
  16. }, []);
  17. }
  18. useCustomHook(ref?.current.querySelectorAll(`li`));
  19. return (
  20. <ul ref={ref}>
  21. {array.map((_, i) => <li key={i}>{i}</li>)}
  22. </ul>
  23. );
  24. }

是否有一种方式可以通过给自定义钩子一个元素数组来实现这一点?

谢谢! 😊

英文:

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 -->

  1. const App = () =&gt; {
  2. const array = [...Array(50).keys()];
  3. const ref = React.useRef(null);
  4. React.useEffect(() =&gt; {
  5. const observer = new IntersectionObserver((entries) =&gt; {
  6. entries.forEach((element: any) =&gt; {
  7. if (element.isIntersecting) {
  8. element.target.style.color = &#39;green&#39;;
  9. }
  10. })
  11. })
  12. ref.current.querySelectorAll(`li`).forEach(element =&gt; {
  13. observer.observe(element);
  14. });
  15. }, [ ]);
  16. return (
  17. &lt;ul ref={ref}&gt;
  18. {array.map((_, i) =&gt; &lt;li key={i}&gt;{i}&lt;/li&gt;)}
  19. &lt;/ul&gt;
  20. )
  21. }
  22. ReactDOM.createRoot(document.getElementById(`root`))
  23. .render(
  24. &lt;React.StrictMode&gt;
  25. &lt;App /&gt;
  26. &lt;/React.StrictMode&gt;
  27. );

<!-- language: lang-html -->

  1. &lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js&quot;&gt;&lt;/script&gt;&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js&quot;&gt;&lt;/script&gt;&lt;div id=&quot;root&quot;&gt;&lt;/div&gt;

<!-- 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 -->

  1. const App = () =&gt; {
  2. const array = [...Array(50).keys()];
  3. const ref = React.useRef(null);
  4. const useCostumeHook = (elements) =&gt; {
  5. React.useEffect(() =&gt; {
  6. const observer = new IntersectionObserver((entries) =&gt; {
  7. entries.forEach((element: any) =&gt; {
  8. if (element.isIntersecting) {
  9. element.target.style.color = &#39;green&#39;;
  10. }
  11. })
  12. })
  13. elements.forEach(element =&gt; {
  14. observer.observe(element);
  15. });
  16. }, [ ]);
  17. }
  18. useCostumeHook(ref?.current.querySelectorAll(`li`))
  19. return (
  20. &lt;ul ref={ref}&gt;
  21. {array.map((_, i) =&gt; &lt;li key={i}&gt;{i}&lt;/li&gt;)}
  22. &lt;/ul&gt;
  23. )
  24. }
  25. ReactDOM.createRoot(document.getElementById(`root`))
  26. .render(
  27. &lt;React.StrictMode&gt;
  28. &lt;App /&gt;
  29. &lt;/React.StrictMode&gt;
  30. );

<!-- language: lang-html -->

  1. &lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js&quot;&gt;&lt;/script&gt; &lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js&quot;&gt;&lt;/script&gt; &lt;div id=&quot;root&quot;&gt;&lt;/div&gt;

<!-- 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已经设置时获取项目:

  1. const useCustomHook = (getElements) => {
  2. React.useEffect(() => {
  3. const observer = new IntersectionObserver((entries) => {
  4. entries.forEach((element) => {
  5. if (element.isIntersecting) {
  6. element.target.style.color = 'green';
  7. }
  8. });
  9. });
  10. const elements = getElements();
  11. elements?.forEach((element) => {
  12. observer.observe(element);
  13. });
  14. }, []);
  15. };

用法:

  1. 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:

  1. const useCostumeHook = (getElements) =&gt; {
  2. React.useEffect(() =&gt; {
  3. const observer = new IntersectionObserver((entries) =&gt; {
  4. entries.forEach((element: any) =&gt; {
  5. if (element.isIntersecting) {
  6. element.target.style.color = &#39;green&#39;;
  7. }
  8. })
  9. })
  10. const elements = getElements();
  11. elements?.forEach(element =&gt; {
  12. observer.observe(element);
  13. });
  14. }, []);
  15. }

Usage:

  1. useCostumeHook(() =&gt; ref.current?.querySelectorAll(`li`))

huangapple
  • 本文由 发表于 2023年2月14日 06:15:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/75441708.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定