2

I'm using ketting for my React REST client. The library provides hooks to access some data, In my case, this is this hook :

import { useResource } from 'react-ketting';
...
const { loading, error, data } = useResource('https://api.example/article/5');

I have multiples resources and I want to loop on them:

items.map(item => {
const { loading, error, data, resourceState } = useResource(item);

 myItems.push({
  title: data.name,
  onClick: () => go(resourceState.links.get('self').href),
 });
});

But React doesn't accept looping the useResource hook like this.

So I found a dirty solution that I'm not proud of...

import React from 'react';
import { useCollection, useResource } from 'react-ketting';

let myItems = [];

const Collection = ({ resource, go }) => {
  const { items } = useCollection(resource);

  myItems = [];

  return (
    <div>
      {items.map(item => (
        <CollectionItem go={go} resource={item} />
      ))}
      <ElementsUser elements={myItems} />
    </div>
  );
};

const CollectionItem = ({ resource, go }) => {
  const { data, resourceState } = useResource(resource);

  myItems.push({
    title: data.name,
    onClick: () => go(resourceState.links.get('self').href),
  });
  return null;
};

Do you have any tips to deal with that problem?

And is it possible that it causes a :

Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.

Evert
  • 93,428
  • 18
  • 118
  • 189
Ugo Lfe
  • 717
  • 2
  • 9
  • 27
  • 1
    You can use a hook within a loop if there's determined items count. If it doesn't change with time, make items.length a ref. Otherwise you'll need to reimplement useResource yourself to operate on multiple items, or move useResource call to nested component. – Estus Flask Mar 18 '21 at 09:00
  • items.length will change over time. This what I did to move useResource to a nested component no? – Ugo Lfe Mar 18 '21 at 09:16
  • 1
    Actually your "dirty" solution is perfectly fine and will work great - as long as you don't need the data resulting from `useResource()` higher in your component tree. – jered Mar 18 '21 at 09:24
  • As useResource() is making an API call, it's possible that causes an error to update state on an unmounted component? – Ugo Lfe Mar 18 '21 at 10:38
  • @UgoLfe Yes, that's what you did and this is legit. A problem with state update possible regardless of where it's located, it would be the same in parent component, and it would be the same for any async side effect that doesn't do a cleanup. Check source code or just check if it cancels an update on unmount. – Estus Flask Mar 18 '21 at 15:26
  • @jered Even if you need, a child can report to a parent. – Estus Flask Mar 18 '21 at 15:26
  • @UgoLfe is your REST client open source? – Evert Mar 21 '21 at 07:39
  • 1
    @Evert No it's a private API under construction. We are trying the power of ketting. – Ugo Lfe Mar 22 '21 at 13:00

1 Answers1

1

Using 1 component per Resource is exactly the pattern that's recommended. I'd even say it's a best practice. Note that a call to useResource will not result in an API call if there was a cached resource state.

If you find that you are seeing 1 request per iteration, you might want to make sure that your collection returns every member as an embedded resource. If you use the useCollection hook, the request will include a Prefer: transclude=item header to give a hint to the server that embedding might be desired.

Also, react-ketting will do cleanups on unmount.

Evert
  • 93,428
  • 18
  • 118
  • 189
  • Hello I have a related post concerning Ketting, in order to manage PUT/POST. https://stackoverflow.com/questions/66987043/how-to-get-notified-when-a-post-is-done-with-ketting – Ugo Lfe Apr 08 '21 at 07:39