Next JS React con Context API
Tags: react, nextjs, context, spanish
Published: 2020-06-19 22:39:28

Uno de mis grandes temores en iniciar con Next.JS y SSR era el hecho de no poder contar con las herramientas CRA (Create React App) me permitia, además de la flexibilidad de la misma.

Una de las herramientas más comúnmente empleada en mis proyectos es Context API; a mi parecer me entrega las herramientas necesarias de una manera facil para poder manejar el estado de los componentes y su representación global en la aplicación.

Para iniciar, usando create-react-next creamos una aplicación con Next y React.  A continuación una definición de cómo uso Context API mediante useContext:

##Context.js
```javascript
import React, { useContext, createContext } from 'react';

//Context
export const AppContext = createContext(null);

//Provider
export const AppContextProvider = ({ children }) => {
  const [variableState, setVariableState] = React.useState(false);

  //ComponentDidMouunt
  React.useEffect(() => {

  }, []);

  //
  const values = React.useMemo(() => (
    { variableState,      // States que seran visibles en el contexto.
      setVariableState,   // Funciones que son exportadas para manejo externo.
    }), 
    [ 
      variableState ]);   // States que serán visibles en el contexto.

  // Interface donde será expuesto como proveedor y envolverá la App.
  return <AppContext.Provider value={values}>{children}</AppContext.Provider>;
}

//
export function useAppContext() {
  const context = useContext(AppContext);

  if(!context){
    console.error('Error deploying App Context!!!');
  }

  return context;
}

export default useAppContext;
```

Mediante el useContext exportamos el Consumer que puede usarlo en cualquier componente, pagina, o función dentro del proyecto.

##home.js
```javascript
import Head from 'next/head'
import { useEffect } from 'react'
import { useAppContext } from '../contexts/AppContext';

export const Home = () => {
  const { variableState, setVariableState } = useAppContext();


  //ComponentDidMouunt
  useEffect(() => {
    setVariableState(true);
   }, [variableState] );

  
  return (
    <div className="container">
      <Head>
        <title>Testing Next.JS with Context and Hooks</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main>
        <h1 className="title">
          CONTEXT APP {`${variableState}`}
        </h1>

        <p className="description">
          Get Started with AppContext API, using ContextAPI.
        </p>
      </main>

      <style jsx>{`
        .container {
          min-height: 100vh;
          padding: 0 0.5rem;
          display: flex;
          flex-direction: column;
          justify-content: center;
          align-items: center;
        }

        main {
          padding: 5rem 0;
          flex: 1;
          display: flex;
          flex-direction: column;
          justify-content: center;
          align-items: center;
        }


        .title a {
          color: #0070f3;
          text-decoration: none;
        }

        .title a:hover,
        .title a:focus,
        .title a:active {
          text-decoration: underline;
        }

        .title {
          margin: 0;
          line-height: 1.15;
          font-size: 4rem;
        }

        .title,
        .description {
          text-align: center;
        }

        @media (max-width: 600px) {
          .grid {
            width: 100%;
            flex-direction: column;
          }
        }
      `}</style>

      <style jsx global>{`
        html,
        body {
          padding: 0;
          margin: 0;
          font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto,
            Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue,
            sans-serif;
        }

        * {
          box-sizing: border-box;
        }
      `}</style>
    </div>
  )
}

export default Home;
```

Es lo mismo que haría en CRA, pero al ejecutarlo:

```
TypeError: Cannot destructure property `variableState` of 'undefined' or 'null'.
```

Bueno, entonces dónde se configura el <Provider>, donde esta <App>, o <Routes> para envolver mi aplicación.  Esta parte es un poco "tricky", se trata de hacer una especie de "Overload" de App.  Para lo cual creamos un archivo _app.js en la carpeta Pages.

```
pages/_app.js
```

Este debe suplantar la entrada de la aplicación, permitiendo envolver el o los proveedores de contextos que se requieran así como todas las funcionalidades o herramientas que requieran esta modalidad de provider.


##_app.js
```javascript
import App, { Container } from 'next/app';
import { AppContextProvider } from "../contexts/AppContext";

class MyApp extends App {
  render() {
    const { Component, pageProps } = this.props;
    return (
      <AppContextProvider>
        <Component {...pageProps} />
      </AppContextProvider>
    );
  }
}

export default MyApp;
```

Se importa el contexto, y después de este corto procedimiento, ya estamos totalmente funcionales.  

[Ver Demo](https://dev.d22mx9tooqjaej.amplifyapp.com/)