No tienes acceso a esta clase

隆Contin煤a aprendiendo! 脷nete y comienza a potenciar tu carrera

Aprende todo un fin de semana sin pagar una suscripci贸n 馃敟

Aprende todo un fin de semana sin pagar una suscripci贸n 馃敟

Reg铆strate

Comienza en:

3D
20H
21M
9S
Curso de Introducci贸n a React.js

Curso de Introducci贸n a React.js

Juan David Castro Gallego

Juan David Castro Gallego

useContext

17/23
Recursos

El hook de contexto nos ayuda a acceder a datos globales de nuestro contexto, desde cualquier componente hijo, sin tener que pasar estos datos por props componente por componente.

Tiene la misma funcionalidad que el consumer de nuestro contexto, pero useContext tambi茅n tiene una manera m谩s sencilla de utilizar y una sintaxis mucho m谩s clara.

Context.Consumer a useContext

import React from 'react';
// Tambi茅n es importante importar nuestro contexto
import { TodoContext } from '../TodoContext';
import { TodoCounter } from '../TodoCounter';
import { TodoSearch } from '../TodoSearch';
import { TodoList } from '../TodoList';
import { TodoItem } from '../TodoItem';
import { CreateTodoButton } from '../CreateTodoButton';

function AppUI() {
  // Desesctructuramos los valores de nuestro contexto
  const {
    error,
    loading,
    searchedTodos,
    completeTodo,
    deleteTodo,
  } = React.useContext(TodoContext);
  
  return (
    
      
      

      
        {error && 

Desesp茅rate, hubo un error...

} {loading &&

Estamos cargando, no desesperes...

} {(!loading && !searchedTodos.length) &&

隆Crea tu primer TODO!

} {searchedTodos.map(todo => ( completeTodo(todo.text)} onDelete={() => deleteTodo(todo.text)} /> ))}
); } export { AppUI };

Ahora solo nos queda utilizar este hook para acceder a nuestro contexto desde los componentes faltantes.

TodoCounter.js

import React from 'react';
import { TodoContext } from '../TodoContext';
import './TodoCounter.css';

function TodoCounter() {
  const { totalTodos, completedTodos } = React.useContext(TodoContext);
  
  return (
    <h2 className="TodoCounter">Has completado {completedTodos} de {totalTodos} TODOsh2>
  );
}

export { TodoCounter };

TodoSearch.js

import React from 'react';
import { TodoContext } from '../TodoContext';
import './TodoSearch.css';

function TodoSearch() {
  const { searchValue, setSearchValue } = React.useContext(TodoContext);
  
  const onSearchValueChange = (event) => {
    console.log(event.target.value);
    setSearchValue(event.target.value);
  };

  return (
    <input
      className="TodoSearch"
      placeholder="Cebolla"
      value={searchValue}
      onChange={onSearchValueChange}
    />
  );
}

export { TodoSearch };

驴Cu谩ndo se recomienda emplear React Context?

  • Estado global
  • Tema
  • Configuraci贸n de la app
  • Autenticaci贸n de usuario
  • Configuraci贸n de usuario
  • Lenguaje preferido
  • Colecci贸n de servicios

Contribuci贸n creada por: Brandon Argel.

Aportes 40

Preguntas 17

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad?

o inicia sesi贸n.

Basicamente, la formula de useContext es

import { Contexto } from './direccionContexto/'

const { value } = React.useContext(Contexto)

Me encanto este video, me venia haciendo mucho ruido la forma de pasar props padre>hijo>nieto>...>x todo el tiempo.
.
Creo que esta t茅cnica es excelente. 驴Hay alguna forma de como investigar sobre estos patrones por asi decirlo, para buscar buenas pr谩cticas de como escribir nuestros componentes en React?
.
Si ya desde el principio comienzo a escribir con buenas pr谩cticas creo que va a ser mejor y har谩 m谩s claro mi c贸digo.

En React, cu谩ndo debo iniciar con mayuscula o minuscula el nombre del archivo como por ejemplo TodoCounter.js o useLocalStorage.js?

Si vienes de Vue, puedes utilizar una herramienta muy similar y mas facil de manejar llamada provide/inject. Buscalo en la documentacion de vue.

provide/inject

No se olviden que el argumento de useContext debe ser nuestro objeto contexto y no por separado el provider o el consumer, como el profe lo habia planteado que podria usarse cuando lo haciamos con la otra t茅cnica sin el hook useContext
.
Correcto: useContext(MiContexto)
Incorrecto: useContext(MiContexto.Consumer)
Incorrecto: useContext(MiContexto.Provider)

Por si a alguien le habia ocurrido un error con el useContext.

Si al usar useContext el componente da error al usar algun objeto del destructuring, es porque donde estas usando el useContext no est谩 presente el Provider.

En caso de que s铆, es porque tienes el provider y el useContext en el mismo componente, y estos van separados.

Por si a alguien le interesa os dejo como implemente el provider y el use context con TypeScript, no se si ser谩 la mejor manera pero por lo que estuve viendo es una de las manera de hacerlo:

Primero de todo cuando hacemos el createContext se le pasa una inteface con todo lo que contendr谩 el context, el tipado si os fij谩is tiene que ser con opci贸n a null puesto que se inicializa a null.

export type TodoContextInterface = {
  createTodoValue: string;
  setTodoValue: React.Dispatch<React.SetStateAction<string>>;
  addTodo: () => void;
  completedTodos: number;
  totalTodos: number;
  searchValue: string;
  setSearchValue: React.Dispatch<React.SetStateAction<string>>;
  toogleFilterComplete: () => void;
  filterComplete: boolean;
  todosFiltered: Todo[];
  completeTodos: (text: string) => void;
  deleteTodos: (text: string) => void;
}

const TodoContext = createContext<TodoContextInterface | null>(null);

Seguido creamos la funci贸n todoProvider que cambia muy poco de la que se hace en JavaScript, solo que en este caso creo el objeto y luego se lo paso al value.

const context: TodoContextInterface = {
    createTodoValue,
    setTodoValue,
    addTodo,
    completedTodos,
    totalTodos,
    searchValue,
    setSearchValue,
    toogleFilterComplete,
    filterComplete,
    todosFiltered,
    completeTodos,
    deleteTodos,
  }

  return (
    <TodoContext.Provider value={context}>
      {props.children}
    </TodoContext.Provider>
  );

La implementaci贸n del TodoProvider en App es exactamente igual.

function App() {
  
  return (
    <TodoProvider>
      <AppUI />
    </TodoProvider>
  );
}

export default App;

A la hora de extraer los datos con use context si cambia algo porque tenemos que hacer comprobaci贸n de que no vengan a null puesto que los inicializamos a null. Por ello en lugar de hacerlo una y otra vez en los componentes cre茅 un customHook que extrae los datos y los devuelve cuando lo llamas. Este hook puede hacerse mas reutilizable pas谩ndole par谩metros pero como no es muy grande la aplicaci贸n tampoco lo vi necesario.

import { useContext } from "react";
import { TodoContext } from "../context/todoContext";

function useTodoContext() {
  const todoContext = useContext(TodoContext);
  
  if(todoContext === null) throw new Error('Todo need a context');

  return todoContext;
}

export { useTodoContext };

Y aqu铆 estar铆a la implementaci贸n en los componentes, en los cuales llamo a mi customHook.

import { useTodoContext } from "../hooks/useTodoContext";

export default function TodoCounter() {
  const { completedTodos, totalTodos } = useTodoContext();

  return (
    <h2 className="subtitle">Completed {completedTodos} to {totalTodos} tasks</h2>
  );
}

Espero os sirva de ayuda y si alguien sabe una manera mejor de implementarlo por favor compartir puesto que no siempre es f谩cil encontrar contenido en TypeScript.

Friendly reminder 馃榿 Al momento de usar la destructuracion podemos renombrar las propiedades para utilizarlas con el nombre tal cual estaban:

const { totalTodos: total, completedTodos: completed } = React.useContext(TodoContext);

explica bien pero. a veces marea con tanta emocion que le coloca por decirlo asi

Me encant贸 este hook.
Ya decia yo que el consumer era un poquito engorroso xd
Al menos no tanto como pasar props como por 5 niveles pero ya que existe useContext sin duda empezar茅 a implementarlo en mis proyectos :3

.
Es como declarar estados globales.

Single responsibility, excelente curso

Eso de cortar sin miedo es peligroso porque te salen mil errores, pero una vez los solucionas te siente un PRO hacker+ de la computaci贸n

Aprovechando esta maravilla de useContext modifiqu茅 mi TodoCounter asi
.

.
Si ya hay TODOs aparece el contador normal

function TodoCounter() {
    const {totalTodos, completedTodos, loading, searchedTodos } = useContext(TodoContext)
    if (!loading && !searchedTodos.length) {
        return (
            <h2 className='TodoCounter'>Crea tu primer TODO 馃挭</h2>
        )
    } else {
        return (
            <h2 className='TodoCounter'>Has completado {completedTodos} de {totalTodos} TODOs 馃挭</h2>
        )
    }
}

venia toda seria siguiente el video y la emoci贸n del 4:31 me hizo estallar de risa 馃ぃ

鈥淣o le tengas miedo a borrar鈥.
No es miedo, es 鈥減recauci贸n鈥 馃槀

En esta clase no romp铆 todo el c贸digo al cortar, copiar, pegar. Voy a tomar eso como una victoria 馃槃

Otra manera de solucionar el problema presentado en el 5:30 es no cambiar las variables total y complete y usar el destructuring assignment para asignarles los valores que vienen de totalTodos y completedTodos.

import React from 'react';
import './TodoCounter.css';
import { TodoContext } from '../TodoContext';

function TodoCounter() {
    const { totalTodos: total, completedTodos: completed } = React.useContext(TodoContext);
    return (
        <h2 className="TodoCounter">Has completado {completed} de {total} TODOs</h2>
    )
}

export { TodoCounter };

useContext acepta un objeto de contexto (el valor devuelto de React.createContext) y devuelve el valor de contexto actual. El valor actual del contexto es determinado por la propiedad value del <MyContext.Provider> ascendentemente m谩s cercano en el 谩rbol al componente que hace la llamada.

Aunque si quieren un tip, yo lo que hice fue renombrar esas variables y dejandolas como estan, no afecta su funcionamiento de toda el componente.

const {totalTodos: total, completedTodos: completed} = React.useContext(TodoContext);
  return (
      <h2 className="TodoCounter">Has completado {completed} de {total} TODOs</h2>
  );

De hecho esto es una mejor manera de consumir el context, es mas legible.

Llevaba un tiempo trabajando con React, lo hab铆a aprendido a tropezones y prueba y error hasta que le cog铆 gusto. Este curso me est谩 abriendo mucho los ojos y haciendo cogerle mucho m谩s gusto y buenas practicas :3

Mi esructura de carpetas por el momento

.
Referencia: https://blog.webdevsimplified.com/2022-07/react-folder-structure/

Cuando emplear React Context!

  • Estado global
  • Tema
  • Configuacion
  • Autenticacion
  • Configuracion de usuario
  • Lenguaje preferido
  • Coleccion de servicios

Cada vez m谩s fan de React

Brutalmente hermoso. Cada vez me enamoro m谩s de React 鉂わ笍

Agregue esta condici贸n para que no muestre el crea tu primer todo si es que estas buscando y no encuentra nada en con el patero. {!loading && !searchedTodos.length && !searchValue && (

Sab铆an
que es una buena practica usar su contexto a trav茅s de un React Hook ?

const useTodoContext = () => {
	// Evaluamos si existe el contexto actual, sino lanzamos un error.
  const context = useContext(TodoContext)
  if (context === undefined) {
    throw new Error('useTodoContext must be used within a TodoContextProvider')
  }
  return context
}

de esta manera tienes m谩s control a la hora de consumir tus contextos (que cuando tu aplicaci贸n crezca pueden llegar a ser MUCHISIMOS.

M谩s informaci贸n en el blog del genio Kent C Dodds

Todo esto es genial, ya quiero desarrollar apps con React jsjs

As铆 qued贸 mi Context:

import { createContext } from 'preact'
import { useState } from "preact/hooks"

import { useLocalStorage } from "../hooks/useLocalStorage"

const TodoContext = createContext()

const TodoProvider = (props) => {

    const [todos, setTodos] = useLocalStorage("TODOS_V1", "[]")
    const [searchValue, setSearchValue] = useState("")

    // Counter scope
    const completed = todos.filter(todo => !!todo.completed).length
    const total = todos.length

    // List scope
    const filteredTodos = todos.filter(todo => todo.text.toLowerCase().includes(searchValue.toLowerCase()))
    let searchedTodos = todos
    if (searchValue.length >= 1) searchedTodos = filteredTodos

    const toggleComplete = (id) => {
        let newTodos = [...todos]
        let selectedTodo = todos.findIndex(todo => todo.id === id)

        newTodos[selectedTodo].completed = !newTodos[selectedTodo].completed;

        setTodos(newTodos)
    }

    const handleDelete = (id) => {
        setTodos(
            todos.filter(todo => todo.id != id)
        )
    }

    const values = {
        // Counter
        completed,
        total,
        // Search
        searchValue,
        setSearchValue,
        // List
        searchedTodos,
        toggleComplete,
        handleDelete,
    }

    return (
        <TodoContext.Provider value={values}>
            {props.children}
        </TodoContext.Provider>
    )
}

export { TodoContext, TodoProvider }

馃槃

si con este hook el codigo es mas legible y hasta facil de hacer.

Estuve batallando horas y horas con mi aplicaci贸n, la tron茅 y no ten铆a idea de porque no estaba funcionando, yo le hechaba la culpa a la funci贸n donde usaba useEffect, puesto que se saltaba esa funci贸n especificamente y no entraba a realizar la llamada de la API, busque por cielo mar y tierra sin saber por qu茅 funcionaba as铆, ahora veo que seguramente comet铆 alg煤n error de sintaxis usando el componente Consumer.
Solo aplique el cambio usando el Hook useContext y listo, asunto arreglado, no quer铆a ver esta clase del curso porque no quer铆a avanzar sin resolver ese problema.
Esto es magia pura jajaja (obvio es broma), me est谩 costando un poco acostumbrarme a los hooks, pero veo que son extremadamente 煤tiles.

Pero que belleza la de useContext. Me encanta jaja

Como pocas clases me da cierta ansidad saber que se va a terminar, es como cuando la serie se pone buena y no queres que termine, que tremendo profesor que es JuanDC

Not茅 que al hacer una b煤squeda que no genere una coincidencia con los TODOS existentes, aparace el mensaje 鈥淐rea tu primer TODO鈥 al igual que cuando no tenemos ning煤n todo en la lista. Mejorar铆a el c贸digo si al componente AppUI le pas贸 tambi茅n la propiedad totalTodos

  const {
    error,
    loading,
    searchedTodos,
    completeTodo,
    deleteTodo,
    totalTodos
  } = React.useContext(TodoContext);

Y luego en el return, dentro del componente TodoList agrego una nueva l铆nea de l贸gica para mostrar un mensaje distinto cuando la b煤squeda no arroje resultados pero s铆 existen TODO鈥檚 en la lista:

            {(!loading && !searchedTodos.length && !!totalTodos) && <p>隆No hay ning煤n TODO que coincida con tu b煤squeda!</p>}
            {(!loading && !totalTodos) && <p>隆Crea tu primer TODO!</p>}

Tambi茅n tuve que agregar la condici贸n de que la lista est茅 vac铆a para que aparezca el mensaje de crear el primer TODO.

No s茅 por qu茅 todo lo que se ha desestructurado en objetos no me funciona 馃槮

Ojala, pudiera llegar al nivel del Prof鈥 no le corre鈥 no funciona鈥 y de una vez observa el c贸digo y encuentra el error鈥 Mientras yo: horas y aun nada鈥

Por si dejan de aparecer los componentes
Solo es poner un 鈥榬eturn鈥 en la funci贸n del Consumer

Buenisimo!

Hola Juan, cada que haces una manera diferente de c贸mo usar x o y cosa explota la App 馃槮

Pregunta de examen:
驴C贸mo usamos React Context con la sintaxis de React Hooks?