Hero

Añadiendo contexto a nuestra aplicación en Next.js

Junio 09, 2022

jperez
Next.js

Hoy estaremos viendo como utilizar el contexto dentro de las aplicaciones de React. Lo primero a tener en cuenta es que el contexto es una forma más sencilla de pasar datos a través del árbol de componentes sin tener que pasar información manualmente en cada nivel.

En una aplicación típica de React, los datos son transmitidos desde arriba hacia abajo a través de props, pero a veces el uso puede ser engorroso para ciertos tipos de props (p. ej., idiomas, tema de interfaz de usuario) puesto que requieren muchos componentes dentro de una aplicación. El contexto sería una forma de compartir valores entre los componentes, ya que está diseñado para compartir datos que se pueden considerar globales para un árbol de componentes, como el usuario autenticado actual, el tema o el idioma preferido.

El contexto se utiliza principalmente cuando algunos datos deben ser accesibles para muchos componentes en diferentes niveles de anidamiento. Se debe aplicar con moderación porque dificulta la reutilización de los componentes.

Teniendo todo esto claro, se comenzará a integrar el contexto en la app ya que se va a traducir la interfaz de usuario de inglés a español, lo primero es crear en la carpeta raíz el directorio lang dentro de src y se crea el archivo language.js con el siguiente código:

const Language = {
  en: {
    menuProducts: 'Products',
    menuCategories: 'Categories',
          . . .
      },
  es: {
    menuProducts: 'Productos',
    menuCategories: 'Categorías',
          . . .
      }
};

export default Language;

Luego, se agrega el directorio contexts dentro de srcy luego, el archivo langContext.js con el siguiente código:

import React from "react";
import Language from "../lang/language";

const LangContext = React.createContext({
  setLanguage: lang => { },
  languages: Language.en,
});

export default LangContext;

Ahora, el archivo será modificado _app.js y se debe agregar el siguiente código:

import React from 'react';
import '../../styles/globals.css';
import 'bootstrap/dist/css/bootstrap.css';
import AdminLayout from '../layouts/AdminLayout';
import LangContext from '../contexts/langContext';
import Language from '../lang/language';

class MyApp extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      setLanguage: this.setLanguage,
      languages: Language.en,
    };
  }

  setLanguage = lang => {
    this.setState({
      languages: Language[lang]
    });
  };

  render() {
    const { Component, pageProps } = this.props;
    return (
      <LangContext.Provider value={this.state}>
        <AdminLayout>
          <Component {...pageProps} />
        </AdminLayout>
      </LangContext.Provider>
    );
  }

}

export default MyApp;

Ahora, en cada componente y página de su aplicación, se puede acceder al idioma y actualizar la interfaz de acuerdo al idioma preferido. Para poder cambiar entre idiomas, se debe agregar al layout AdminLayout.js un campo que permita cambiar entre los lenguajes:

import React from 'react';
import Sidebar from '../components/sidebar';
import LangContext from '../contexts/langContext';

class AdminLayout extends React.Component {

  render() {
    return (
            . . .
    < LangContext.Consumer >
      {({ setLanguage }) => (
        <div className='col'>
          <select className="form-select" onChange={e => setLanguage(e.target.value)}>
            <option value="en">English</option>
            <option value="es">Spanish</option>
          </select>
        </div>
      )
    }
    </LangContext.Consumer>
            . . .
    );
  }
}

export default AdminLayout;

Listo, ahora en cada componente que se necesite, se debe agregar el siguiente pedazo de código y se podrá actualizar la interfaz según el idioma que seleccione el usuario:

return (
  <LangContext.Consumer>
    {({ languages }) => (
          . . .
      )}
  </LangContext.Consumer>
)

Por ejemplo, acá se añadió el código anterior en uno de los componentes ya creados:

import React from 'react';
import LangContext from '../contexts/langContext';

/**
 * This is a product form component.
 */
class ProductForm extends React.Component {
        . . .

  render = () => {
    return (
      <LangContext.Consumer>
        {({ languages }) => (
          <div className='card mb-2 mt-2'>
            <div className='card-body'>
              <h5 className="card-title">{languages.addProduct}</h5>
              <hr className='divider' />
              <form method='post' name='form-product'>
                <div className='row mb-2'>
                  <div className="col">
                    <input type="text"
                      className="form-control"
                      id="product_name"
                      name="product_name"
                      placeholder={languages.phProductName}
                      value={this.state.product_name}
                      required={true}
                      onChange={e => this.onChangedData(e, 'product_name')} />
                  </div>
                  <div className="col">
                    <input type="number"
                      className="form-control"
                      id="product_quantity"
                      name="product_quantity"
                      placeholder={languages.phQuantity}
                      value={this.state.quantity}
                      required={true}
                      onChange={e => this.onChangedData(e, 'quantity')} />
                  </div>
                  <div className="col">
                    <input type="number"
                      className="form-control"
                      id="product_price"
                      name="product_price"
                      placeholder={languages.phPrice}
                      value={this.state.price}
                      required={true}
                      onChange={e => this.onChangedData(e, 'price')} />
                  </div>
                  <div className="col">
                    <select placeholder='Select a category'
                      className="form-select"
                      id="category"
                      name="category"
                      value={this.state.category}
                      required={true}
                      onChange={e => this.onChangedData(e, 'category')}>
                      <option value={'-1'}>{languages.phSelect}</option>
                      {
                        this.state.categories.map((c, i) => <option key={i} value={c._id}>{c.category_name}</option>)
                      }
                    </select>
                  </div>
                  <div className='col'>
                    <div className="d-grid gap-2 d-md-flex">
                      {this.showButtons()}
                    </div>
                  </div>
                </div>
              </form>
            </div>
          </div>
        )}
      </LangContext.Consumer>
    );
  }
}

ProductForm.contextType = LangContext;

export default ProductForm;

Aquí esta el código completo para comprobar como se agrega el contexto en toda la app: https://github.com/jjosequevedo/products-translation-ui La app debe funcionar ahora con la traducción, acá una captura de pantalla de como debería verse:

Recibe consejos y oportunidades de trabajo 100% remotas y en dólares de weKnow Inc.