[Contexto de React] El uso de Contexto en React

I. Resumen

El contexto proporciona una forma de compartir valores entre componentes sin tener que pasar accesorios explícitamente a través de las capas del árbol de componentes. Si los niveles de obtención del valor y uso del valor están muy separados, o si hay muchos componentes que necesitan usar este valor y están dispersos, puede usar Contexto para compartir datos y evitar usar una gran cantidad de accesorios repetidos para pasar valores. Si solo un componente necesita usar este valor, puede generar este componente en la ubicación donde se genera este valor y luego usar accesorios para pasarlo capa por capa a la ubicación de visualización real del componente.

2. Uso básico

1. Contexto personalizado

import React from 'react';
 
const ThemeContext = React.createContext('light');
 
export default ThemeContext;

El código anterior define un ThemeContext con un valor predeterminado de 'light'.

2. Use el proveedor de contexto donde sea necesario

import ThemeContext from './context/ThemeContext.js';
import ThemedButton from './ThemedButton.js';
import './App.css';
 
function App() {
    
    
  return (
    <ThemeContext.Provider value='dark'>
      <div className="App">
        <header className="App-header">
          <ThemedButton />
        </header>
      </div>
    </ThemeContext.Provider>
  );
}
 
export default App;

El proveedor del Contexto personalizado se usa en la capa más externa del componente, y el valor entrante anula el valor predeterminado, y luego el valor de ThemeContext leído por el subcomponente es "oscuro" en lugar del valor predeterminado "claro". Si el proveedor tiene una definición de valor, se utilizará el valor del valor (incluso si el valor no está definido, es decir, no se pasa ningún valor), y solo cuando el proveedor no lo proporciona, el valor predeterminado en el momento de definición se utilizará.

3. Defina el tipo de contexto y use el valor obtenido del Contexto

import React, {
    
     Component } from 'react';
import ThemeContext from "./context/ThemeContext.js";
 
class ThemedButton extends Component {
    
    
	static contextType = ThemeContext;
	render() {
    
    
		return <button>{
    
    this.context}</button>;
	}
}
 
export default ThemedButton;

ThemedButton declara que contextType es ThemeContext, por lo que el valor de this.context es el valor proporcionado por el ThemeContext más cercano, que es 'light'.

Representaciones:
inserte la descripción de la imagen aquí

4. El nombre de Contexto
El Contexto declarado de la manera anterior solo mostrará Context.Porvider cuando se visualice el árbol de componentes, y no mostrará ThemeContext:

inserte la descripción de la imagen aquí

Esto es un inconveniente para ver cuando hay varios proveedores Para definir el nombre para mostrar de Contexto, puede declararlo con displayName al definir:

import React from 'react';
 
const ThemeContext = React.createContext('light');
ThemeContext.displayName = 'ThemeContext';
 
export default ThemeContext;

De esta forma, el árbol de componentes mostrará el nombre del Contexto.

inserte la descripción de la imagen aquí

3. Mecanismo de actualización de contexto

Si el atributo de valor del proveedor es una variable, cuando el valor cambia, el subcomponente que consume el proveedor activará el mecanismo de actualización, implementando así también la actualización. Si el valor cambia se juzga por el método de Object.is, por lo tanto, no use objetos generados dinámicamente como el valor del contexto, como:

<ThemeContext.Provider value={
    
    {
    
     theme: 'light' }}><ThemeContext.Provider />

Dado que el valor al que apunta value es un objeto recién generado cada vez que se representa, el puntero de memoria siempre es diferente, lo que hace que la actualización del componente que consume este proveedor se active cada vez. Así que usa una variable para llevar este valor.

1. El ciclo de vida
App.js desencadenado por la actualización de contexto

import React, {
    
     Component } from 'react';
import ThemeContext from './context/ThemeContext.js';
import ThemedButton from './ThemedButton.js';
import './App.css';
 
class App extends Component {
    
    
 
  constructor(props) {
    
    
    super(props);
    this.state = {
    
    
      theme: 'dark'
    };
  }
 
  switchTheme = () => {
    
    
    let {
    
     theme } = this.state;
    theme = theme === 'dark' ? 'light' : 'dark';
    this.setState({
    
     theme });
  }
 
  render() {
    
    
    return (
      <ThemeContext.Provider value={
    
    this.state.theme}>
        <div className="App">
          <header className="App-header">
            <ThemedButton onClick={
    
    this.switchTheme} />
          </header>
        </div>
      </ThemeContext.Provider>
    );
  }
}
 
export default App;

BotónTemático.js

import React, {
    
     Component } from 'react';
import ThemeContext from "./context/ThemeContext.js";
 
class ThemedButton extends Component {
    
    
	static contextType = ThemeContext;
 
	componentDidUpdate() {
    
    
		console.log('ThemedButton componentDidUpdate');
	}
 
	shouldComponentUpdate() {
    
    
		console.log('ThemedButton shouldComponentUpdate');
		return false;
	}
 
	render() {
    
    
		console.log('ThemedButton render');
		return <button onClick={
    
    this.props.onClick}>{
    
    this.context}</button>;
	}
}
 
export default ThemedButton;

Salida en la actualización:
inserte la descripción de la imagen aquí

La actualización de Context no se ve afectada por el componente principal y su propio shouldComponentUpdate, y el ciclo de vida es render->componentDidUpdate.

2. Tanto la actualización de accesorios como la actualización de contexto activan
el ciclo de vida desencadenado por la actualización de accesorios: shouldComponentUpdate->render->componentDidUpdate.Si se produce la actualización de contexto, se activará el ciclo de vida superpuesto de los dos, es decir, render->componentDidUpdate. Por lo tanto, si es necesario desencadenar el ciclo de vida shouldComponentUpdate, debe evitarse que se active al mismo tiempo que la actualización de contexto.

4. Use Consumer para respaldar la obtención de valores en múltiples contextos

1. Método básico de uso
Si necesita usar valores en varios contextos, solo un tipo de contexto no es suficiente. Debe usar el Consumidor proporcionado por Contexto para obtener los valores en el Contexto correspondiente.

Declare dos tipos de contexto:

import React from 'react';
 
const ThemeContext = React.createContext('light');
ThemeContext.displayName = 'ThemeContext';
 
export default ThemeContext;
import React from 'react';
 
const UserContext = React.createContext('guest');
UserContext.displayName = 'UserContext';
 
export default UserContext;

Usar asignación de proveedor:

import React, {
    
     Component } from 'react';
import ThemeContext from './context/ThemeContext.js';
import UserContext from './context/UserContext.js';
import ThemedButton from './ThemedButton.js';
import './App.css';
 
class App extends Component {
    
    
 
  constructor(props) {
    
    
    super(props);
  }
 
  render() {
    
    
    return (
        <ThemeContext.Provider value={
    
    'dark'}>
          <div className="App">
            <UserContext.Provider value={
    
    'user'}>
              <header className="App-header">
                <ThemedButton />
              </header>
            </UserContext.Provider>
          </div>
        </ThemeContext.Provider>
    );
  }
}
 
export default App;

Utilice los valores proporcionados por estos dos Contextos en ThemedButton:

import React, {
    
     Component } from 'react';
import ThemeContext from "./context/ThemeContext.js";
import UserContext from "./context/UserContext.js";
 
class ThemedButton extends Component {
    
    
 
	render() {
    
    
		return (
			<>
				<ThemeContext.Consumer>
					{
    
    theme => <div>{
    
    theme}</div>}
				</ThemeContext.Consumer>
				<UserContext.Consumer>
					{
    
    user => <div>{
    
    user}</div>}
				</UserContext.Consumer>
			</>
		);
	}
}
 
export default ThemedButton;

Dentro del alcance del paquete Consumer, puede utilizar el valor proporcionado por el Proveedor correspondiente, de esta manera, puede consumir los valores proporcionados por múltiples tipos de Proveedores en un componente.

2. Comparación entre contextType y Consumer
El contextType solo puede apuntar a un contexto en un componente, y luego el valor proporcionado por el proveedor correspondiente se puede usar en cualquier parte del componente a través de this.context. La desventaja es que solo se puede usar un Contexto. El consumidor puede usar múltiples para obtener el valor de diferentes tipos de proveedores. Sin embargo, debido a la sintaxis de las etiquetas, solo se puede usar en render y ámbitos relacionados. Los componentes deben usar Consumer tanto como sea posible para obtener el valor en Context, y dejar la posición de contextType para evitar que no haya contextType para usar cuando contextType debe usarse más adelante.

Cinco, contexto personalizado

En la definición de Contexto anterior, solo se definen Contexto y el nombre de visualización correspondiente, y Context.Provider y Context.Consumer se utilizan para su uso posterior.Este lenguaje de etiquetas es difícil de entender. Además, cuando se asigna un valor a Provider, se usa el atributo de valor, que no refleja el significado exacto, especialmente cuando hay varios valores para pasar. Por lo tanto, debe haber las siguientes partes al personalizar el Contexto:

import React from 'react';
import PropTypes from 'prop-types';
 
// 枚举值
const THEMES = {
    
    
	DARK: 'dark',
	LIGHT: 'light'
};
// 默认值
const defaultValue = THEMES.DARK;
// Context
const ThemeContext = React.createContext(defaultValue);
// Context展示名
ThemeContext.displayName = 'ThemeContext';
// Consumer
const ThemeConsumer = ThemeContext.Consumer;
// Provider
const ThemeProvider = ({
    
     theme, children }) => (
	<ThemeContext.Provider value={
    
    theme}>
		{
    
    children}
	</ThemeContext.Provider>
);
 
ThemeProvider.propTypes = {
    
    
 
	theme: PropTypes.oneOf(['dark', 'light']),
 
	children: PropTypes.oneOfType([
		PropTypes.element,
		PropTypes.arrayOf(PropTypes.element)
	]),
}
 
export {
    
     THEMES, ThemeContext, ThemeConsumer, ThemeProvider };

al usarlo:

import React, {
    
     Component } from 'react';
import {
    
     ThemeProvider, THEMES } from './context/ThemeContext.js';
import ThemedButton from './ThemedButton.js';
import './App.css';
 
class App extends Component {
    
    
 
  render() {
    
    
    // 不再需要ThemeContext.Provider和value,用更易理解的标签取代
    return (
      <ThemeProvider theme={
    
    THEMES.LIGHT}>
        <div className="App">
          <header className="App-header">
            <ThemedButton />
          </header>
        </div>
      </ThemeProvider>
    );
  }
}
 
export default App;
import React, {
    
     Component } from 'react';
import {
    
     ThemeConsumer } from "./context/ThemeContext.js";
 
class ThemedButton extends Component {
    
    
 
  render() {
    
    
    // 用ThemeConsumer取代ThemeContext.Consumer
    // 也可以用contextType = ThemeContext,ThemeContext也有导出
    // 但是如之前所说,不到万不得已不使用只有一个位置的contextType
    return (
      <ThemeConsumer>
        {
    
    theme => <div>{
    
    theme}</div>}
      </ThemeConsumer>
    );
  }
}
 
export default ThemedButton;

Seis, el uso de useContext

React introdujo Hook en la versión 16.8, que le permite usar el estado y otras características de React sin escribir una clase. useContext es uno de los ganchos nativos. Es un componente de función que también puede usar contexto y admite el uso de múltiples tipos diferentes de contexto. Entonces, si usa componentes de función, puede usar useContext para admitir el uso de múltiples tipos diferentes de valores de contexto.

Proporcione el valor de Contexto sigue siendo el mismo código:

import React, {
    
     Component } from 'react';
import {
    
     ThemeProvider, THEMES } from './context/ThemeContext.js';
import UserContext from './context/UserContext';
import ThemeAndUser from './ThemeAndUser';
import './App.css';
 
class App extends Component {
    
    
 
  render() {
    
    
    return (
      <ThemeProvider theme={
    
    THEMES.LIGHT}>
        <UserContext.Provider value={
    
    'user'}>
          <div className="App">
            <header className="App-header">
              <ThemeAndUser />
            </header>
          </div>
        </UserContext.Provider>
      </ThemeProvider>
    );
  }
}
 
export default App;

Use useContext para obtener el valor en Contexto:

import {
    
     useContext } from 'react';
import {
    
     ThemeContext } from './context/ThemeContext';
import UserContext from './context/UserContext';
 
const ThemeAndUser = () => {
    
    
	const theme = useContext(ThemeContext);
	const user = useContext(UserContext);
	return (
		<>
			<div>{
    
    theme}</div>
			<div>{
    
    user}</div>
		</>
	);
};
 
export default ThemeAndUser;

7. Resumen

El contexto se utiliza para proporcionar contenido accesible globalmente con un mecanismo de actualización controlable. Pero trate de no usarlo a menos que sea necesario.
El contexto no solo puede pasar valores, sino también funciones. Puede pasar el valor en el contexto junto con la función para actualizar el valor.
contextType solo puede apuntar a un contexto y usar un valor de contexto. El uso de Context.Consumer puede usar varios valores de contexto, pero solo en el renderizado y sus funciones relacionadas.
useContext también puede usar varios valores de contexto, pero solo se puede usar en componentes de funciones.

8. Referencias

1. Documentación oficial en chino de React sobre el uso de Context: https://zh-hans.reactjs.org/docs/context.html

2. Documentación oficial en chino de React sobre el uso de useContext: https://zh-hans.reactjs.org/docs/hooks-reference.html#usecontext

————————————————
Declaración de derechos de autor: este artículo es un artículo original del blogger CSDN "sysukehan", siguiendo el acuerdo de derechos de autor CC 4.0 BY-SA, adjunte el enlace de la fuente original y este declaración para su reimpresión.
Enlace original: https://blog.csdn.net/sysukehan/article/details/114039009

Supongo que te gusta

Origin blog.csdn.net/hzxOnlineOk/article/details/130011954
Recomendado
Clasificación