¿Cómo usar de forma correcta Context en react? Parte 1
Tags: react, hook, contextapi
Published: 2022-11-29 18:12:42


Primero hay que entender para que usaremos context en nuestras aplicaciones.
- Administración de estado
- Componentes de acceso global.

Para la administración de estados dispones de combinaciones con `useState` y `useReducer`.
De esta forma lo usaremos para administrar nuestro estado de forma global. Primero definiendo nuestro context, lo llamaremos **AuthenticationContext**, pero para resumir será **AuthContext**.

```ts
import React, { useCallback, useMemo } from 'react';

interface IUserInfo {
    uuid: string;
    username: string;
    email: string;
    name: string;
}

export interface IAuthContext {
  userInfo?: IUserInfo;
  setUserInfo: (user: IUserInfo) => void;
  onLogin: (username: string) => Promise<IUserInfo | undefined>;
  onLogout: () => Promise<void>;
}

export const AuthContext = React.createContext<IAuthContext>({
  userInfo: undefined,
  setUserInfo: (user) => {
    throw new Error('Not yet implemented');
  },
  onLogin: (username) => {
    throw new Error('Not yet implemented');
  },
  onLogout: () => {
    throw new Error('Not yet implemented');
  },
});
```
Nuestro **AuthContext** está compuesto por **userInfo** este atributo contendrá la información del usuario, **setUserInfo** nos permite asignar la información del usuario, **onLogin** nos permite ejecutar la petición para realizar el inicio de sesión en nuestra app.
Ahora es necesario definir nuestro **Provider**, este nos permitirá agregar la lógica necesaria para darle funcionalidad a nuestra aplicación. El nombre correcto para nuestro proveedor será **AuthProvider** y este hará uso del **AuthContext**.
```ts
interface Props {
  children: JSX.Element;
}

export const AuthProvider = ({ children }: Props): JSX.Element  => {
  const { userInfo, setUserInfo } = useState<IUserInfo | undefined>(undefined);

  // Iniciar Sesión
  const onLogin = useCallback(
    async (username) => {
      const user = await fetch(<server_user_login>);
      setUserInfo(user);
      return user;
    }, [setUserInfo]);

  // Cerrar sesión
  const onLogout = useCallback((userInfoLogout) => {
    await fetch(<server_user_logout>);
    setUserInfo(undefined);
  }, [setUserInfo]);

  const values = React.useMemo<IAuthContext>(() =>({
    userInfo,
    setUserInfo,
    onLogin,
    onLogout
  }))

  return (
    <AuthContext.Provider value={...values}>
      {children}
    </AuthContext.Provider>
  );
};

export default AuthProvider;
```

Haciendo uso de un `useState` manejaremos nuestro estado userInfo, para nuestras funciones `onLogin` y `onLogout` son las encargadas de conectar nuestra app con el servidor usando peticiones HTTP usando `fetch` o `axios`.
Ya solo nos falta exponer los datos para poder hacer uso de ellos. Hacerlo de la siguiente manera nos permite centralizar el contexto y nos ahorramos una serie de validaciones, por ello usamos un `hook`.
```ts
import { useContext } from 'react';

import { AuthContext, IAuthContext } from 'context/authContext';

export function useAuth(): IAuthContext {
  const context = useContext(AuthContext);

  if (!context) {
    throw new Error('useAuth may be used inside of AuthContext');
  }

  return context;
}
```

## ¿Y como usamos todo esto ahora?
En nuestra app debemos integrar el Provider.
```ts
import { AuthProvider } from 'context/authContext';

const App = () => {
  return (
    <AuthProvider>
      ...
    </AuthProvider>
  );
};

export default App;
```
Y para usar los datos en nuestros componentes tenemos la siguiente via
```ts
import { useAuth } from 'hooks/useAuth';
import { useClosable } from 'hooks/useClosable';
import { SimpleConfirmDialog } from 'components/SimpleConfirmDialog';

export const LogoutButton = () => {
  const { onLogout } = useAuth();
  const [open, onOpen, onClose] = useClosable();
  
  return (
    <>
    <Tooltip title="Cerrar Sesión">
      <IconButton
        onClick={onOpen}
        type="submit"
        color="secondary"
        edge="end"
        >
          <ExitToAppIcon />
      </IconButton>
    </Tooltip>
    <SimpleConfirmDialog
      open={open}
      onClose={onClose}
      onConfirm={onLogout}
      title="Cerrar sesión"
      />
  </>)
}
```
Haciendo uso del `hook` **useAuth** traemos toda la lógica que hemos centralizado en los procesos anteriores y esto hace más sencillo la creación de componentes dependientes de nuestro proveedor.

> Espero que esta primera parte de esta entrada sea de gran ayuda a la hora de crear Contextos y proveedores en sus aplicaciones escritas en react.