loading...

Conditional hooks, maybe

theonlybeardedbeast profile image TheOnlyBeardedBeast ・1 min read

Most of the times I can handle development with react hooks without additional tricks. Until today I had no issue with the rules of react-hooks, but today was the day when everything changed.

We use a third-party hook that handles the persistence of the state in our simple form, but it does not handle the case if the local storage is not available. We requested a fallback implementation in the third-party hook but we still needed a fix, a temporary fix maybe.

Hooks can't be used inside conditions, and I needed to use a different hook based on the local storage availability.

Here is my solution:

const getHook = () => {
  try {
    // this throws an error if the localstorage is not available
    window.localStorage.getItem('key'); 

    return usePersistence;
  } catch {
    return useState;
  }
};

The getHook function tests the local storage then it returns the right hook based on the trycatch success state.

Based on this solution we need to get an initial value (because our hooks use different initial values)

const getInitialValue = () => {
  try {
    window.localStorage.getItem('contact-form');

    return 'contact-form';
  } catch {
    return {};
  }
};

So now we have a fallback for our third-party hook and the right initial value for each case.

The usage is the following:

// inside the functional component
const [formValues, setFormValues] = getHook()(getInitialValue());

Not the nicest solution, but it works.

English isn’t my first language, so please excuse any mistakes.

Thank you all for your attention and time, hopefully, my solution won't last long in the project.

Posted on by:

theonlybeardedbeast profile

TheOnlyBeardedBeast

@theonlybeardedbeast

.NET Core + TypeScript + React + Flutter + UWP Yep, that's me.

Discussion

pic
Editor guide
 

Indeed you should't get your Hook in a conditionnal way.

Not sure what you wanna do exactly but you can create a custom Hook like that :

function useStateWithPersistance(initialValueIfNotFound) {
  let initialValue = initialValueIfNotFound;
  try {
    initialValue = localStorage.getItem("whatever");
  } catch {}

  const [whatever, setWhatever] = useState(initialValue);

  function setWhateverWithPersistance(val) {
    try { 

       localStorage.setItem("whatever", val);
    } catch (e) {}
    setWhatever(val);
  }

  return [whatever, setWhateverWithPersistance];
}
 

You can then use it like a useState.

And you can generalize the name of the storage key as a second parameter of your custom hook in order to reuse you hook anywhere you want.

 

Thank you, but the persist library did much more then just saving into the localstorage there was debouncing and much more, now the library is updated and the temporary fix is not used anymore.