React Hook "useSubscribe" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function

Right now I get React Hook "useSubscribe" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function. error on my code and try to find a way to make this work.

  const TodosList = useMemo(() => {
    return lists?.map((list) => {
      return (
        <div key={list._id}>
          {list?.todos?.map((todo) => {

            const commentLoading = useSubscribe('card', todo._id);
            const todos = useFind(
              () =>
                Todos.find(
                  {
                    todo._id,
                  },
                  {sort: {createdAt: 1}},
                ),
              [todo._id, commentLoading()],
            );
  
            return (
              {
                todos.map((todo) => (
                  <Todo key={todo._id} />
                ))
              }
            )
          }
          )}
        </div>
      );
    });
  }, [lists]);

I’m getting the error because I have useSubscribe and useFind inside of useMemo.

Instead of doing this, what could I try?

Thank you in advance!

You can’t put the hooks inside the render (return stagement) function.
You should not use one subscription for each “card” component you have in a list. It’s expensive.

Your component should look like this:

const TodosList = useMemo(() => {
  const todoIds = list?.todos.map((todo) => todo._id);
  const commentLoading = useSubscribe('cards', todoIds); // use once subscription only
  const todos = useFind(
    // find them
  );
      return (
        <div>
          {todos?.map((todo) => {
               return   <Todo key={todo._id} data={todo} />
          })}
        </div>
      );
  }, [lists]);
2 Likes

Hmm I have used useFind and useSubscribe before return statement like you suggested, I’m still getting the exactly same error message.

If your TodosList is a react component then

Replace

const TodosList = useMemo(() => {

by

const TodosList = React.memo(({ list }) => {

Else, you must move these block

const todoIds = list?.todos.map((todo) => todo._id);
  const commentLoading = useSubscribe('cards', todoIds); // use once subscription only
  const todos = useFind(
    // find them
  );

To outside of useMemo statement, or just remove the useMemo. I don’t know why you need to use useMemo here.

1 Like

It works! Thank you very much!

1 Like