# React Hooks Personnalisés : useNetworkState

Après avoir implémenté le Hook [useLocalStorage](https://blog.iamludal.fr/react-hooks-personnalises-uselocalstorage)
pour faciliter la gestion du stockage local, implémentons le Hook `useNetworkState` pour connaître
l'état du réseau de l'utilisateur (savoir s'il est connecté à internet ou non).

## Motivation

Supposons que nous soyons en train de développer une application qui nécessite d'être connecté à internet
en permanence pour fonctionner convenablement. Si l'utilisateur se retrouve déconnecté, un message doit être
affiché, lui informant de vérifier sa connectivité. Pour ce faire, dans une application React, voici
comment nous pourrions procéder.

```jsx
const App = () => {
  const [isOnline, setIsOnline] = useState(window.navigator.onLine);

  useEffect(() => {
    const handleOnline = () => setIsOnline(true);
    const handleOffline = () => setIsOnline(false);

    window.addEventListener('online', handleOnline);
    window.addEventListener('offline', handleOffline);

    return () => {
      window.removeEventListener('online', handleOnline);
      window.removeEventListener('offline', handleOffline);
    };
  }, []);

  return (
    <div>
      <h1>My Awesome App</h1>
      <p>
        Lorem, ipsum dolor sit amet consectetur adipisicing elit. Culpa
        provident tenetur molestias fugiat expedita quaerat dolores dignissimos
        dicta, error amet reiciendis voluptates delectus perspiciatis dolorum
        saepe, sunt, similique vitae illo.
      </p>
      {!isOnline && (
        <div className="toast">
          You are offline. Please check your connectivity and try again.
        </div>
      )}
    </div>
  );
};
```

Ceci fonctionne parfaitement. En revanche, notre code pourrait considérablement être simplifié, notamment le
Hook `useEffect`. Notre but est donc de définir un Hook `useNetworkState` afin d'abstraire cette logique dans
un Hook séparé. Cela permettra à la fois de simplifier notre composant, mais aussi (et surtout) de pouvoir 
réutiliser cette logique à d'autres endroits de notre application sans dupliquer de code. Maintenant que nous
savons pourquoi nous avons besoin de ce Hook, passons à l'implémentation. 👨🏻‍💻


## Implémentation

Comme à notre habitude, réfléchissons d'abord à l'interface de notre Hook afin de savoir comment nous allons
l'utiliser. Dans notre cas, nous voudrions quelque chose d'aussi simple que ça :

```jsx
const isOnline = useNetworkState()
```

Ni plus, ni moins. Il nous retournerait une simple valeur booléenne qui sera mise à jour automatiquement
et convenablement pour se synchroniser avec l'état actuel de la connectivité de l'utilisateur.

Nous pouvons donc passer à l'implémentation, qui consistera tout simplement en l'extraction de la logique
que nous avons écrite précédemment au sein d'une fonction séparée. Le Hook final n'est donc pas plus
compliqué que ça :

```jsx
const useNetworkState = () => {
  const [isOnline, setIsOnline] = useBoolean(window.navigator.onLine);

  useEffect(() => {
    window.addEventListener('online', setIsOnline.on);
    window.addEventListener('offline', setIsOnline.off);

    return () => {
      window.removeEventListener('online', setIsOnline.on);
      window.removeEventListener('offline', setIsOnline.off);
    };
  }, []);

  return isOnline;
};
```

> Euh, c'est quoi ce Hook `useBoolean` ? 🤨

Effectivement, il n'est pas fourni directement par React. Cependant, pour ceux qui suivraient cette série
depuis le tout début, ce Hook devrait vous rappeler quelque chose : c'est le tout premier Hook personnalisé
que nous avons implémenté ensemble !

Si vous avez découvert cette série en cours de route, pas d'inquiétude : je vous invite à lire
[cet article](https://blog.iamludal.fr/react-hooks-personnalises-useboolean) pour en apprendre plus sur ce Hook.

> Si vous ne souhaitez pas utiliser le Hook `useBoolean`, vous pouvez vous contenter d'un simple `useState`.

```jsx
const useNetworkState = () => {
  const [isOnline, setIsOnline] = useState(window.navigator.onLine);

  useEffect(() => {
    const handleOnline = () => setIsOnline(true);
    const handleOffline = () => setIsOnline(false);

    window.addEventListener('online', handleOnline);
    window.addEventListener('offline', handleOffline);

    return () => {
      window.removeEventListener('online', handleOnline);
      window.removeEventListener('offline', handleOffline);
    };
  }, []);

  return isOnline;
};
```


## Utilisation

Si nous reprenons notre composant `App` de tout à l'heure, voici comment il peut être simplifié
grâce à notre tout nouveau Hook :

```jsx
const App = () => {
  const isOnline = useNetworkState()

  return (
    <div>
      <h1>My Awesome App</h1>
      <p>
        Lorem, ipsum dolor sit amet consectetur adipisicing elit. Culpa
        provident tenetur molestias fugiat expedita quaerat dolores dignissimos
        dicta, error amet reiciendis voluptates delectus perspiciatis dolorum
        saepe, sunt, similique vitae illo.
      </p>
      {!isOnline && (
        <div className="toast">
          You are offline. Please check your connectivity and try again.
        </div>
      )}
    </div>
  );
};
```

Eh oui, je vous l'avais dit, notre code est désormais bien plus simple ! 😎


## Conclusion

Nous avons réussi à abstraire toute la logique de connectivité réseau à l'extérieur de notre composant,
qui se concentre maintenant sur ce qu'il doit réellement faire. Grâce à cela, nous suivons le principe
de séparation des préoccupations, ou Separation of Concerns en anglais (SOC). Vous trouverez plus
d'informations sur [ce lien](https://fr.wikipedia.org/wiki/S%C3%A9paration_des_pr%C3%A9occupations).
Dans le prochain article, nous allons implémenter un Hook pour utiliser plus facilement les effets
sonores : `useAudio`.

---

Code source disponible sur [CodeSandbox](https://codesandbox.io/s/custom-react-hooks-usenetworkstate-354j0?file=/src/App.tsx).

