Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Hook "useTranslation" is called in function "getMyMenu" that is neither a React function component nor a custom React Hook function

I am invoking the useTranslation hook from within a normal function as below

import { useTranslation } from "react-i18next";


function getMyMenu(a) {
  const { t } = useTranslation('translations');
  
  if (a.showRoute) {
      a.label = t(a.label);
    return a;
  }
}



export const MyNav = props => {
  let tabs = recurseFn(getMyMenu, props.routes);
}

I get the following error. Is there no way to fix this? For some strange reason, I was able to see the similar code pattern working in other project. Any additional config needed to make this work?

Updated:

This is how my recurseFn looks like:

export const recurseFn = (chk, [head, ...tail]) => {
  if (head === undefined) return [];
  if (chk(head)) {
    return [head, ...recurseFn(chk, tail)];
  }

  return [...recurseFn(chk, tail)];
};
like image 288
copenndthagen Avatar asked Apr 27 '26 15:04

copenndthagen


1 Answers

You can fix it by moving the useTranslation hook to the MyNav component body and pass the translation function t as a closure in getMyMenu.

import { useTranslation } from "react-i18next";

export const MyNav = props => {
  const { t } = useTranslation('translations');

  function getMyMenu(a) {
    if (a.showRoute) {
      a.label = t(a.label);
      return a;
    }
  }

  let tabs = recurseFn(getMyMenu, props.routes);

  ...
}

Edit

I just updated with how my recurseFn looks like. Is it possible to pass "t" to it?

Solution 1 - Pass t explicitly to all functions

You could certainly update the function signature of recurseFn to also consume a "t" (translation?) function, but you'd still need to then also pass t into chk which would necessitate updating the original getMyMenu function to consume an additional argument.

Example:

function getMyMenu(t, a) { // <-- consume additional t argument
  if (a.showRoute) {
      a.label = t(a.label);
    return a;
  }
}

...

export const recurseFn = (chk, [head, ...tail], t) => { // <-- consume additional t argument
  if (head === undefined) return [];
  if (chk(t, head)) { // <-- pass t to chk
    return [head, ...recurseFn(chk, tail, t)]; // <-- pass t on recursion
  }

  return [...recurseFn(chk, tail, t)]; // <-- pass t on recursion
};

...

import { useTranslation } from "react-i18next";

export const MyNav = props => {
  const { t } = useTranslation('translations');

  let tabs = recurseFn(getMyMenu, props.routes, t); // <-- pass t on recursion

  ...
}

Solution 2 - A better solution using a curried callback

In this case I think making getMyMenu a curried function can help you enclose t in the callback and allow it to be declared externally to any React component. The recurseFn function doesn't need to know anything about t, so why expose it there, right?

const getMyMenu = t => a => {
  if (a.showRoute) {
    a.label = t(a.label);
    return a;
  }
}

Now you destructure t from the useTranslation hook return value and pass to the curried getMyMenu function. This is a similar idea to closing over the t function in the callback like we did above in the first answer.

import { useTranslation } from "react-i18next";

export const MyNav = props => {
  const { t } = useTranslation('translations');

  let tabs = recurseFn(getMyMenu(t), props.routes);

  ...
}

Now from recurseFn's perspective, t is enclosed in the chk callback and recurseFn didn't need to explicitly handle receiving and passing t around.

like image 193
Drew Reese Avatar answered Apr 29 '26 06:04

Drew Reese



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!