We want to hear from you!Take our 2021 Community Survey!
Este sitio ya no se actualiza.Vaya a react.dev

Context

Estos documentos son antiguos y no se actualizarán. Vaya a react.dev para ver los nuevos documentos de React.

Estas nuevas páginas de la documentación enseñan React moderno e incluyen ejemplos interactivos:

La nueva documentación reemplazará próximamente este sitio, que será archivado. Deja tu opinión aquí

Context provee una forma de pasar datos a través del árbol de componentes sin tener que pasar props manualmente en cada nivel.

En una aplicación típica de React, los datos se pasan de arriba hacia abajo (de padre a hijo) a través de props, pero esta forma puede resultar incómoda para ciertos tipos de props (por ejemplo, localización, el tema de la interfaz) que son necesarias para muchos componentes dentro de una aplicación. Context proporciona una forma de compartir valores como estos entre componentes sin tener que pasar explícitamente una prop a través de cada nivel del árbol.

Cuándo usar Context

Context está diseñado para compartir datos que pueden considerarse “globales” para un árbol de componentes en React, como el usuario autenticado actual, el tema o el idioma preferido. Por ejemplo, en el código a continuación, pasamos manualmente una prop de “tema” para darle estilo al componente Button:

class App extends React.Component {
  render() {
    return <Toolbar theme="dark" />;
  }
}

function Toolbar(props) {
  // El componente Toolbar debe tener un prop adicional "theme"  // y pasarlo a ThemedButton. Esto puede llegar a ser trabajoso  // si cada botón en la aplicación necesita saber el tema,  // porque tendría que pasar a través de todos los componentes.  return (
    <div>
      <ThemedButton theme={props.theme} />    </div>
  );
}

class ThemedButton extends React.Component {
  render() {
    return <Button theme={this.props.theme} />;
  }
}

Usando Context podemos evitar pasar props a través de elementos intermedios:

// Context nos permite pasar un valor a lo profundo del árbol de componentes// sin pasarlo explícitamente a través de cada componente.// Crear un Context para el tema actual (con "light" como valor predeterminado).const ThemeContext = React.createContext('light');
class App extends React.Component {
  render() {
    // Usa un Provider para pasar el tema actual al árbol de abajo.    // Cualquier componente puede leerlo, sin importar qué tan profundo se encuentre.    // En este ejemplo, estamos pasando "dark" como valor actual.    return (
      <ThemeContext.Provider value="dark">        <Toolbar />
      </ThemeContext.Provider>
    );
  }
}

// Un componente en el medio no tiene que// pasar el tema hacia abajo explícitamente.function Toolbar() {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

class ThemedButton extends React.Component {
  // Asigna un contextType para leer el contexto del tema actual.  // React encontrará el Provider superior más cercano y usará su valor.  // En este ejemplo, el tema actual es "dark".  static contextType = ThemeContext;
  render() {
    return <Button theme={this.context} />;  }
}

Antes de usar Context

Context se usa principalmente cuando algunos datos tienen que ser accesibles por muchos componentes en diferentes niveles de anidamiento. Aplícalo con moderación porque hace que la reutilización de componentes sea más difícil.

Si solo deseas evitar pasar algunos props a través de muchos niveles, la composición de componentes suele ser una solución más simple que Context.

Por ejemplo, considera un componente Page que pasa una prop user y avatarSize varios niveles hacia abajo para que los componentes anidados Link y Avatar puedan leerlo:

<Page user={user} avatarSize={avatarSize} />
// ... que renderiza ...
<PageLayout user={user} avatarSize={avatarSize} />
// ... que renderiza ...
<NavigationBar user={user} avatarSize={avatarSize} />
// ... que renderiza ...
<Link href={user.permalink}>
  <Avatar user={user} size={avatarSize} />
</Link>

Puede parecer redundante pasar los props de user yavatarSize a través de muchos niveles si al final solo el componente Avatar realmente lo necesita. También es molesto que cada vez que el componente Avatar necesite más props, también hay que agregarlos en todos los niveles intermedios.

Una forma de resolver este problema sin usar Context es pasar el mismo componente Avatar para que los componentes intermedios no tengan que saber sobre los props usuario o avatarSize:

function Page(props) {
  const user = props.user;
  const userLink = (
    <Link href={user.permalink}>
      <Avatar user={user} size={props.avatarSize} />
    </Link>
  );
  return <PageLayout userLink={userLink} />;
}

// Ahora tenemos:
<Page user={user} avatarSize={avatarSize} />
// ... que renderiza ...
<PageLayout userLink={...} />
// ... que renderiza ...
<NavigationBar userLink={...} />
// ... que renderiza ...
{props.userLink}

Con este cambio, solo el componente más importante Page necesita saber sobre el uso de user y avatarSize de los componentes Link y Avatar.

Esta inversión de control puede hacer que tu código, en muchos casos, sea más limpio al reducir la cantidad de props que necesitas pasar a través de tu aplicación y dar más control a los componentes raíz. Sin embargo, esta inversión no es la opción correcta en todos los casos. Al mover más complejidad a niveles superiores del árbol, esos componentes en los niveles superiores resultan más complicados y obliga a los componentes en niveles inferiores a ser más flexibles de lo que podría ser deseable.

No estás limitado a un solo hijo por componente. Puede pasar varios hijos, o incluso tener varios “huecos” (slots) separados para los hijos, como se documenta aquí:

function Page(props) {
  const user = props.user;
  const content = <Feed user={user} />;
  const topBar = (
    <NavigationBar>
      <Link href={user.permalink}>
        <Avatar user={user} size={props.avatarSize} />
      </Link>
    </NavigationBar>
  );
  return (
    <PageLayout
      topBar={topBar}
      content={content}
    />
  );
}

Este patrón es suficiente para muchos casos cuando necesitas separar a un componente hijo de sus componentes padres inmediatos. Puedes llevarlo aún más lejos con render props si el hijo necesita comunicarse con el padre antes de renderizar.

Sin embargo, a veces, los mismos datos deben ser accesibles por muchos componentes en el árbol y a diferentes niveles de anidamiento. Context te permite “transmitir” dichos datos, y los cambios, a todos los componentes de abajo. Los ejemplos comunes en los que el uso de Context podría ser más simple que otras alternativas incluyen la administración de la configuración de localización, el tema o un caché de datos.

API

React.createContext

const MyContext = React.createContext(defaultValue);

Crea un objeto Context. Cuando React renderiza un componente que se suscribe a este objeto Context, este leerá el valor de contexto actual del Provider más cercano en el árbol.

El argumento defaultValue es usado únicamente cuando un componente no tiene un Provider superior a él en el árbol. Este valor por defecto puede ser útil para probar componentes de forma aislada sin contenerlos. Nota: pasar undefined como valor al Provider no hace que los componentes que lo consumen utilicen defaultValue.

Context.Provider

<MyContext.Provider value={/* algún valor */}>

Cada objeto Context viene con un componente Provider de React que permite que los componentes que lo consumen se suscriban a los cambios del contexto.

El componente Provider acepta una prop value que se pasará a los componentes consumidores que son descendientes de este Provider. Un Provider puede estar conectado a muchos consumidores. Los Providers pueden estar anidados para sobreescribir los valores más profundos dentro del árbol.

Todos los consumidores que son descendientes de un Provider se vuelven a renderizar cada vez que cambia la prop value del Provider. La propagación del Provider a sus consumidores descendientes (incluyendo .contextType y useContext) no está sujeta al método shouldComponentUpdate, por lo que el consumidor se actualiza incluso cuando un componente padre evita la actualización.

Los cambios se determinan comparando los valores nuevos y antiguos utilizando el mismo algoritmo que Object.is.

Nota

La forma en que se determinan los cambios puede causar algunos problemas al pasar objetos como value: mira las Advertencias.

Class.contextType

class MyClass extends React.Component {
  componentDidMount() {
    let value