¡Bienvenida! Este es un curso especial de React Hooks

1

¿Qué aprenderás en el Curso Profesional de React Hooks?

2

¿Qué son los React Hooks y cómo cambian el desarrollo con React?

Introducción a React Hooks

3

useState: estado en componentes creados como funciones

4

useEffect: olvida el ciclo de vida, ahora piensa en efectos

5

useContext: la fusión de React Hooks y React Context

6

useReducer: como useState, pero más escalable

7

¿Qué es memoization? Programación funcional en JavaScript

8

useMemo: evita cálculos innecesarios en componentes

9

useRef: manejo profesional de inputs y formularios

10

useCallback: evita cálculos innecesarios en funciones

11

Optimización de componentes en React con React.memo

12

Custom hooks: abstracción en la lógica de tus componentes

13

Third Party Custom Hooks de Redux y React Router

Configura un entorno de desarrollo profesional

14

Proyecto: análisis y retos de Platzi Conf Store

15

Git Hooks con Husky

16

Instalación de Webpack y Babel: presets, plugins y loaders

17

Configuración de Webpack 5 y webpack-dev-server

18

Configuración de Webpack 5 con loaders y estilos

19

Loaders de Webpack para Preprocesadores CSS

20

Flujo de desarrollo seguro y consistente con ESLint y Prettier

Estructura y creación de componentes para Platzi Conf Store

21

Arquitectura de vistas y componentes con React Router DOM

22

Maquetación y estilos del home

23

Maquetación y estilos de la lista de productos

24

Maquetación y estilos del formulario de checkout

25

Maquetación y estilos de la información del usuario

26

Maquetación y estilos del flujo de pago

27

Integración de íconos y conexión con React Router

Integración de React Hooks en Platzi Conf Merch

28

Creando nuestro primer custom hook

29

Implementando useContext en Platzi Conf Merch

30

useContext en la página de checkout

31

useRef en la página de checkout

32

Integrando third party custom hooks en Platzi Conf Merch

Configura mapas y pagos con PayPal y Google Maps

33

Paso a paso para conectar tu aplicación con la API de PayPal

34

Integración de pagos con la API de PayPal

35

Completando la integración de pagos con la API de PayPal

36

Paso a paso para conectar tu aplicación con la API de Google Maps

37

Integración de Google Maps en el mapa de checkout

38

Creando un Custom Hook para Google Maps

Estrategias de deployment profesional

39

Continuous integration y continuous delivery con GitHub Actions

40

Compra del dominio y despliega con Cloudflare

Optimización de aplicaciones web con React

41

Integración de React Helmet para mejorar el SEO con meta etiquetas

42

Análisis de performance con Google Lighthouse

43

Convierte tu aplicación de React en PWA

Bonus: trabaja con Strapi CMS para crear tu propia API

44

Crea una API con Strapi CMS y consúmela con React.js

¿Qué sigue en tu carrera profesional?

45

Próximos pasos para especializarte en frontend

Crea una cuenta o inicia sesión

¡Continúa aprendiendo sin ningún costo! Únete y comienza a potenciar tu carrera

useEffect: olvida el ciclo de vida, ahora piensa en efectos

4/45
Recursos

Aportes 152

Preguntas 14

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Cada día tengo mayor fluidez con React 😍

¡Hola!
Aquí comparto mi solución al reto:

Escribí un artículo en mi blog que quizás les ayude a complementar los conocimientos que Oscar transmitió en esta clase ❤❤
.
Link del articulo: https://dartiles.dev/blog/useeffect-react-hooks-ciclos-de-vida
.

.
Este blog es un claro reflejo de los conocimientos que adquirí en el curso practico de sapper y svelte de Oscar

Comparto el useEffect usando asyn/await

import React, { useState, useEffect } from "react";

const Characters = () => {
  const [characters, setCharacters] = useState([]);

  const getCharacters = async () => {
    const response = await fetch("https://rickandmortyapi.com/api/character");
    const data = await response.json();
    setCharacters(data.results);
  };

  useEffect(() => {
    getCharacters();
  }, []);

  return (
    <div className="Characters">
      {characters.map((character) => (
        <h2 key={character.id}>{character.name}</h2>
      ))}
    </div>
  );
};

export default Characters;

useEffect: olvida el ciclo de vida, ahora piensa en efectos


useEffect nos permite manejar efectos que van a ser transmitidos dentro del componente.
En este ejemplo se llama a una API, traemos la información y la ejecutaremos en el componente

  1. Creamos el componente Characters.jsx
  2. Usamos el API de RickandMorty


Characters.jsx

// importar useState y useEffect
import React, {useState, useEffect} from 'react'


const Characters = () => {
    /**
     * Lógica de useState
     * constante donde internamente estructuramos los elementos que necesitamos
     * de useState y lo iniciamos como un vector vacío
     */
    const [characters, setCharacters] = useState([]);
    
    /**
     * Lógica de useEffect
     * es una función con 2 parámetros
     * el primero es una función anónima donde va a estar la lógica
     * el segundo es una variable que esta escuchando si hay cambios 
     */
    useEffect(() => {
        // useEffect llama a fetch, el cual obtiene la informacion de la api de RickAndMorty
        fetch('https://rickandmortyapi.com/api/character/')
        .then(response => response.json())
        .then(data => setCharacters(data.results));
    }, [])
    
    /** 
     * Nombre del personaje
     * Iteramos por cada uno de los elementos
     */
    return (
        <div className="Characters">
            {characters.map(character => (
                <h2>{character.name}</h2>
            ))}
        </div>
    )
}

export default Characters


App.js

import React from 'react'
// Importamos componente Header
import Header from './components/Header';
// Importamos componente Characters
import Characters from './components/Characters';
import './App.css';

function App() {
  return (
    <div className="App">
      <Header />
      <Characters />
      <h1>
        Hola Mundo
      </h1>
    </div>
  );
}

export default App;

Como el darkmode es una variable global, subí la logica al nivel de App.js y desde header solo retorno la función que hace el cambio de color.

Usando bootstrap con sus clases para definir colores de texto y fondo, rapidamente puedes hacer este efecto de darkmode y responsive.

import "./App.css";
import React, { useState } from "react";

import { Header } from "./components/Header";
import Characters from "./components/Characters";

function App() {
  const [darkMode, setDarkMode] = useState(false);
  let bg = darkMode ? "bg-dark text-light" : "bg-light text-dark"
  return (
    <>
        <div className= {"App "+ bg}>
          <Header
            darkMode={darkMode}
            onClick={() => setDarkMode(!darkMode)}
          ></Header>
          <Characters></Characters>
        </div>
      
    </>
  );
}

export default App;
import React from 'react'

export const Header =( props )=>{
    
    return(
        <div className="Header ">
            <h1>React Hooks</h1>
            <button type="button" onClick={()=>props.onClick()}>
                {props.darkMode ? "Light Mode" : "Dark Mode"}
            </button>
        </div>

    )
}


import React, { useEffect, useState } from "react";

const Characters = () => {
  const [characters, setCharacters] = useState([]);

  useEffect(() => {
    fetch("https://rickandmortyapi.com/api/character/")
      .then((r) => r.json())
      .then((data) => setCharacters(data.results));
  }, []);

  return (
    <div className="container">
            
        <div className="row">
      {characters.map((character) => (
        <div className="col">
          <>
          <img className="character__img" src={character.image} alt="" />
          <h2 className="character__name">{character.name}</h2>
          </>
          </div>
          ))}
    </div>
    </div>
  );
};

export default Characters;

Usando tailwindcss

import React, { useState, useEffect } from 'react';

const Characters = () => {
  const [characters, setCharacters] = useState([]);
  const API = 'https://rickandmortyapi.com/api/character/';
  useEffect(() => {
    fetch(API)
      .then(response => response.json())
      .then(data => setCharacters(data.results));
  }, []);

  return (

    <section className="text-gray-700 body-font ">

      <div className="flex flex-col text-center w-full mb-20">
        <h1 className="sm:text-3xl text-2xl font-medium title-font mb-4 text-gray-900">Rick and Morty</h1>
        <p className="lg:w-2/3 mx-auto leading-relaxed text-base">All Characters</p>
      </div>
      <div className="container px-5 mx-auto ">
        <div className=" flex flex-wrap -m-2">
          {characters.length > 0 && characters.map(character => (
            <div className="p-2 lg:w-1/3 md:w-1/2 w-full">
              <div className="h-full flex items-center border-gray-200 border p-4 rounded-lg">
                <img alt="team" className="w-16 h-16 bg-gray-100 object-cover object-center flex-shrink-0 rounded-full mr-4" src={character.image} />

                <div className="flex-grow">
                  <h2 className="text-gray-900 title-font font-medium">{character.name}</h2>
                  <p className="text-gray-500">{character.status}</p>
                  <p className="text-gray-500">{character.species}</p>

                </div>
              </div>
            </div>
          ))}
        </div>

      </div>
    </section>
  );
};

export default Characters;

useEffect

Nos ayuda con todo lo que tiene que ver con efectos secundarios. Algunos ejemplos de efectos secundarios son:

-Peticiones de datos

-Establecimiento de suscriptores

-Actualizaciones manuales del DOM

**Características de useEffect **

-Recibe dos parámetros: el primero una función y el segundo un array cuyos valoren serán variables de las que depende nuestro efecto(este array es opcional).

-Se va a ejecutar en cada renderizado del componente incluyendo el primero.

-Puedes usar más de un useEffect x componente

-Está diseñado para que la función que pases como parámetro retorna a su vez otra función, React va a ejecutar dicha función cuando se desmonte el componente

(BONUS) Como funciona el ciclo de vida de un componente?

OJO el ciclo de vida de un componente es un concepto para trabajar con componente de tipo clases, pero se me hacía interesante entender como funcionaba.

Veremos solo como funciona por encima cada ciclo tiene sus propios componentes para poder manejarlo.

El ciclo de vida de React se puede dividir en 3 fases, que son: Él montando, la actualización y el desmontado

Montado: Esta es la primera fase y ocurre una vez por componente cuando este se crea y se monta en la UI.

Actualización: Esta puede ocurrir ninguna o múltiples veces, esta fase sucede cuando ocurre algún cambio en el componente y por lo tanto requiere que la UI se vuelva a generar para que se puedan percibir estos cambios.

Desmontado: Es la última fase y se puede ejecutar un método antes de que se desmonte el componente de la UI.

¿Cuál es la diferencia entre el useEffect y los metodos del ciclo de vida?

La diferencia esta en que cuando usamos useEffect no pensamos en el cuando(en que fase estamos) si no, en el por qué el efecto se va a ejecutar(cambios en una dependencia).

Para profundizar les comparto lo siguiente blog: https://matiashernandez.dev/react-useeffect-hook-comparado-con-los-estados-del-ciclo-de-vida

https://platzi.com/blog/ciclo-de-vida-de-un-componente-de-reactjs/#:~:text=El ciclo de vida se,o después de cierta acción.

Challenge done

Asi va quedando el mio:

Y así quedo. 😃

Esta es mi solución al reto, utilice una API que encontré de Breaking Bad para retarme y ver que realmente comprendi todo! (antes de este curso hice el de consumo de API muy recomendado)

En este articulo Dan Abramov explica el useEffect a profundidad
https://overreacted.io/a-complete-guide-to-useeffect/

Para realizar el cambio de estilo hice un levantamiento de estado, es decir pase el estado de darkMode en Header.jsx hacia App.js. Me quedo algo asi:

Header.jsx

import React from 'react';

import 'bootstrap/dist/css/bootstrap.css';

const Header = (props) => {
  // const [darkMode, setDarkMode] = useState(false);
  // const appClass = document.getElementById('header');
  // console.log(appClass);
  
  return (
    <div id="header" className="Header">
      <h1>ReackHooks</h1>
      <button 
      className="btn btn-dark"
      onClick={props.onHandleClick} 
      type="button"
      >
          {
          props.darkMode?
          'DarkMode':
          'LightMode'
          }
      </button>
    </div>
  )}
          
export default Header;

En app.js

import React, { useState } from "react";

import Character from "./components/Character";
import Header from "./components/Header";

import "./App.css";

function App() {
  const [darkMode, setDarkMode] = useState(false);

  const handleClick = () => {
    setDarkMode(!darkMode);
    const candleButton = document.querySelector(".App");
    const title = document.querySelector(".App__title");

    candleButton.classList.toggle("dark-background");
    title.classList.toggle("dark-title");
  };
  return (
    <div className="App">
      <h1 className="App__title">Rick and Morty Characters</h1>
      <Header onHandleClick={handleClick} darkMode={darkMode} />
      <Character />
    </div>
  );
}

export default App;

En el navegador…
.
LightMode

.
.
DarkMode

Me faltó el dark/light mode, pero mañana continuo xD

Comparto mi versión del ejercicio

Apuntes

  • Dejar de usar el ciclo de vida y pensar en efectos
  • Nos permite manejar efectos los cuales serán transmitidos dentro de nuestros componentes
    • Trabajando lógica interna según sea el caso

conceptos claves
useEffect.- El Hook de efecto te permite llevar a cabo efectos secundarios en componentes funcionales:

useEffect hace disponibles los métodos del ciclo de vida componentDidMount, componentDidUpdate y componentWillUnmount combinados en componentes funcionales. Tener presente que si no se pasa un array como segundo argumento:

useEffect(() => {
	// aquí va el código
});

el código dentro de useEffect se ejecutará cada vez que el componente se re-renderiza (la primera vez que es renderizado y en cada actualización). Similar a componentDidMount y componentDidUpdate.

Pasando un array vacío como segundo argumento:

useEffect(() => {
	// aquí va el código
},  []);

el código se ejecuta una vez cuando el componente es montado (componentDidMount).

Pasando un array no vacío como segundo argumento:

useEffect(() => {
	// aquí va el código
},  [value])

el código se ejecutará cada vez que el valor (value) cambia. También puedes pasar mútiples valores y React renderiza el componente si cualquiera de los elementos del arreglo cambió.

useEffect puede retornar una función el cual se ejecuta cuando el componente se desmonta (componentWillUnmount).

useEffect(() => {
	// código
	return () => {
		// código
	}
});

Usando el hook de Efecto

Me hice un componente simple usando sass :B

import React, { useState, useEffect } from 'react';
import '../styles/Characters.sass';

const Characters = () => {
	const [Characters, setCharacters] = useState([]);
	useEffect(() => {
		fetch('https://rickandmortyapi.com/api/character/')
			.then(res => res.json())
			.then(data => setCharacters(data.results));
	}, []);
	return (
		<div class="container">
			{Characters.map(character => (
				<div className="card">
					<figure>
						<img src={character.image} alt="" />
					</figure>
					<h2>{character.name}</h2>
					<p>{character.status}</p>
					<p>{character.species}</p>
					<p>{character.gender}</p>
					<p>{character.location.name}</p>
				</div>
			))}
			<h2>{}</h2>
		</div>
	);
};

export default Characters;

.container
	display: flex
	flex-wrap: wrap
	justify-content: center
.card
	padding: 4%
	text-align: start
	margin: 10px
	border-radius: 10px
	box-shadow: 1px 1px 9px 1px #1d010125
	figure
		img
			width: 100px

Bueno para agregar el DarkMode y LightMode agrege estas lineas de codigo en el Componente Header.

const Header = () => {
  const [mode, setMode] = useState(false)
  
  const onHandleClick= ()=>{
    setMode(!mode);
  } 

  if(mode){
    document.documentElement.style.setProperty('--background-App','#282c34')
    document.documentElement.style.setProperty('--font-color','white')
  }else{
    document.documentElement.style.setProperty('--background-App','white')
    document.documentElement.style.setProperty('--font-color','black')
    
  }
  
  return (
    <div className='header'>
      <h1>React Hooks</h1>
      <button type='button' onClick={onHandleClick} >{mode ? "DarkMode" : "LigthMode"}</button>
    </div>
  );
}
export default Header


El resultado:

Para usar los atajos de los que habla el profesor, hay que instalar la siguiente extensión, ya que la que puso en los links de apoyo no contiene estos atajos 😃

https://marketplace.visualstudio.com/items?itemName=EQuimper.react-native-react-redux

Creo que falto explicar la funcion del return dentro de un -useEffect-

useEffect(() => {
  // aqui se ejecuta las funciones del efecto;
  return () => {
    //aqui se ejecuta el Desmontaje del Efecto;
	// esto es lo que me refiero
  }
}, [props.ActualizaEstado])

Les dejo este Link, en el minuto 19:40 empiezan a explicar la funcion del return
https://www.youtube.com/watch?v=kPx2qgDS3ak&list=PLvq-jIkSeTUZ5XcUw8fJPTBKEHEKPMTKk&index=17&t=594s

Les comparto mi solución para el estilizado utilize Semantic UI recomiendo mucho ese Framework

Una peculiaridad de useEffect es que la función que le pasamos (effect) se ejecuta despues del primer render y despues de cada update. Es como si cada efecto perteneciera a un render en particular

No se les olvide colocarle el key al elemento h2 para evitar los warnings en consola.

<h2 key={character.id}>{character.name}</h2> 

Usando asincronía a la llamada de la API:

const apiURL = 'https://rickandmortyapi.com/api/character/';

  useEffect(() => {
    async function fetchCharacters() {
      const response = await fetch(apiURL);
      const characters = await response.json();
      setCharacters(characters.results);
    }
    fetchCharacters();
  }, []);

Ah caray pensé que haríamos un e-commerce 😅

Reto

  • Character.jsx
import React ,{useState, useEffect}from 'react'
import '../css/characters.css'

const Characters = () => {
    
    const [characters, setCharacters] = useState ([]);

    useEffect(() => {
        fetch('https://rickandmortyapi.com/api/character/')
        .then(response => response.json())
        .then(data => setCharacters(data.results));
    },[])

    return (
    <div className='Characters'>
        {characters.map(character => (
            <div className='Characters-card'>
                <img src={character.image} alt={`imagen de ${character.name}`}/>
                <h2 className='Characters-title'>{character.name}</h2>
                <p className='Characters-paragraph'><b>ID:</b> {character.id}</p>
                <p className='Characters-paragraph'><b>Estatus:</b> {character.status}</p>
                <p className='Characters-paragraph'><b>Especie:</b> {character.species}</p>
                <p className='Characters-paragraph'><b>Genero:</b> {character.gender}</p>
            </div>
        ))}
    </div>
  );
}
export { Characters } 
  • Character.css
.Characters{
    display: grid;
    grid-template-columns: 1fr 1fr 1fr 1fr;
    grid-template-rows: auto;
    gap: 16px;
    padding: 24px;
}
.Characters-card{
    padding: 4px;
    box-shadow: 0px 0px 8px 1px #9e9e9e;
}
.Characters-title{
    margin: 8px;
}
.Characters-paragraph{
    margin: 0;
}

Gracias a todos los aportes de los companeros 😃 Ahi practicando con Tailwinds

return (
        <div className="Characters container px-5 mx-auto">
            <div className=" flex flex-wrap -m-2">
            {characters.length > 0 && characters.map(character => (
            <div className="p-2 lg:w-1/3 md:w-1/2 w-full">
              <div className="h-full flex items-center border-gray-200 border p-4 rounded-lg">
                <img alt="team" className="w-16 h-16 bg-gray-100 object-cover object-center flex-shrink-0 rounded-full mr-4" src={character.image} />
                <div className="flex-grow">
                  <h2 className="text-900 title-font font-medium">{character.name}</h2>
                  <p className="text-gray-400">{character.status}</p>
                  <p className="text-gray-400">{character.species}</p>
                </div>
              </div>
            </div>
          ))}
            </div>   
        </div>
    );

Para instalar sass en React utiliza el siguiente comando:
npm i sass
Para más informacion aqui la pagina oficial:
https://create-react-app.dev/docs/adding-a-sass-stylesheet/

Para aprender un poco más de useEffect
Hay una parte muy importante de este hook llamada cleanup, se utiliza como su nombre lo dice, para limpiar o eliminar las acciones del efecto. No siempre es necesario usarlo, pero es mejor conocerlo a luego tener un problema de optimización grave.

Recomiendo el siguiente artículo para saber un poco más del mismo:
React useEffect cleanup: How and when to use it

Así quedo mi maquetación! tomando un poco el estilo de la web de la API

En App.js

import React, { useState } from 'react';

import Header from './components/Header';
import Characters from './components/Characters';
import './App.css';

function App() {
  const [darkMode, setDarkMode] = useState(false);

  const handleClick = () => {
    setDarkMode(!darkMode);
  }

  return (
    <div className={`App ${darkMode ? 'dark-mode' : 'light-mode'}`}>
      <Header handleClick={handleClick} darkMode={darkMode} />
      <Characters />
    </div>
  );
}

export default App;

Header.jsx

import '../assets/styles/components/Header.css';

const Header = props => {
    const { handleClick, darkMode } = props
    return (
        <div className={`header`}>
            <h1>ReactHooks</h1>
            <button className={`button-mode ${darkMode ? 'light-mode' : 'dark-mode'}`} type="button" onClick={handleClick}>{darkMode ? 'Light mode' : 'Dark mode'}</button>
        </div>
    );
}

export default Header;

useEffect

💡 INFO
Función para realizar efectos secundarios.
Se puede pensar como un símil de los métodos del ciclo de vida componentDidMount, componentDidUpdate y componentWillUnmount combinados, pero sin bloquear el proceso de actualización de la vista.

.
Se puede considerar como efectos secundarios como:

  • Obtención de datos
  • Configuraciones
  • Cambios manuales/predefinidos del DOM
    .

En conjunto, hay 2 tipos de efectos secundarios: los que requieren y no de limpieza.
.

💡INFO
Se dice limpieza/barrido al recurso que necesita, por lógica, encadenar un proceso ya sea por actualización o desmontaje.

.

Efectos sin limpieza

Ejemplos como:

  • Peticiones de red
  • Mutaciones manuales del DOM
    .
import React, { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
  • Al usar de esta forma useEffect , le comunicamos a React que el componente necesita realizar algo después de un renderizado.
  • La función se ejecuta en cada primer renderizado y después de cada actualización.

.

💡INFO
useEffect se ejecuta en cada primer renderizado y después de cada actualización.

.

Efectos con limpieza

Ejemplos como:

  • Registro de sesión/subscripción
import React, { useState, useEffect } from 'react';

function FriendStatus(props) {
  const [isOnline, setIsOnline] = useState(null);

  **useEffect**(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }
    ChatAPI.**subscribeToFriendStatus**(props.friend.id, handleStatusChange);

    return function **cleanup**() {
      ChatAPI.**unsubscribeFromFriendStatus**(props.friend.id, handleStatusChange);
    };
  });

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}
  • Dentro de useEffect , cuando se retorna una función, indicamos el modo en que se limpia/barre.
  • La función cleanup es de fines prácticos, se debe utilizar arrow functions
return () => {
	ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };

💡 INFO
React lanza una limpieza cuando el componente se desmonta o como acción previa a cada siguiente efecto.

.
El API de useEffect permite un parámetro adicional indicando 2 efectos:

  • [] - Si deseamos ejecutar un efecto y limpiarlo una vez, desvinculando la función de los cambios de los props o state , por consiguiente estos últimos dentro de la función siempre tendrán sus valores iniciales.
  • [vale] - Se omite el flujo natural de la función, ejecutándose solamente cuando el valor ha cambiado.

.

Ejemplo Characters.jsx

import React, { useState, useEffect } from "react";

const Characters = () => {
  const [characters, setCharacters] = useState([]);
  useEffect(() => {
    async function fetchCharacters() {
      const response = await fetch("https://rickandmortyapi.com/api/character");
      const data = await response.json();
      setCharacters(data.results);
    }
    fetchCharacters();
  }, []);

  return (
    <div className="characters">
      {characters.length > 0 &&
        characters.map(({ id, name }) => <h2 key={id}>{name}</h2>)}
    </div>
  );
};

export default Characters;

⚠️ NOTA
Pese que CRA o Create React App incorpora React dinámico para no implementarlo, se sugiere definirlo por estabilidad a nivel componente

Les comparto como quedó mi diseño

Este es el código para implementar el Dark Mode

Anduve haciendolo aplicando mobile first:
Mobile:

Tablet:

Desktop:

Modo oscuro:

Observación: Faltó establecer un key para cada elemento interado.

Nota sobre useEffect
Al pasar como segundo parámetro de useEffect un arreglo vacío quiere decir que useEffect se ejecutará solo cuando se monte el componente, si queremos que se ejecute cada vez que se actualice el componente no pondremos ningún parámetro. Si queremos que se actualice cada vez que algo cambie, dentro del arreglo pondremos dicho parámetro a escuchar, y si queremos hacer algo cuando se desmonte el componente retornaremos esa acción en la función de useEffect.

Comparto mis resultados hasta el momento:

Empezando el curso tome la decision de revisar la documentacion de hooks de react mientras pasaba por cada uno, y realmente fue una decision excelente, les recomiendo leer la doc mientras pasan por cada hook, ademas de aprender como funciona completamente el hook tambien te ofrecen buenas practicas al momento de utilizar lo hooks

De essta manera se puede construir el efecto utilizando async/await. que vuelve el codigo y el manejo de la asincronia muhco mas legible

import { useEffect, useState } from "react";

const Character = (props) => {
  const [characters, setCharacters] = useState([]);

  useEffect(() => {
    const fetchCharacters = async () => {
      const response = await fetch("https://rickandmortyapi.com/api/character");
      const data = await response.json();
      setCharacters(data.results);
    };

    fetchCharacters();
  }, []);

  return (
    <div className="charachters">
      {characters.map((character) => {
        return <h2> {character.name} </h2>;
      })}
    </div>
  );
};

export default Character;

Estas clases me han servido para llevar a cabo unas animaciones en mi portfolio 💪

Ahora queda perfeccionarlas y añadirle el Dark Mode 👀

Si quieres ver cómo lo hice, te dejo por aquí el enlace al repo 😄
He de decir que, además de useState y useEffect, tuve que saber algunas cosas acerca del react-router-dom, pero no es muy complicado si lo quieres hacer 😉

Les recomiendo esta lectura de la documentación oficial de React Hooks en español sobre el uso de el hook useEffect . Pensé en resumirla pero es mucho mejor darle una lectura completa para esclarecer cualquier duda.
https://es.reactjs.org/docs/hooks-effect.html

Cumpliendo el reto

Asi me fue…

Aqui mi reto realizado:
LightMode

DarkMode

Muy bueno, por lo general lo que ponía dentro del effect y que actualizaba el state se quedaba en un ciclo infinito de renderizado. ahora veo que es por ese segundo parametro de dicho hooks en donde se pone las variables que escucharán. Y que si se deja vació solo hace el render una vez.

Pude hacer lo del renderizado, pero no lo de darkmode, ya que eso estaba en el Header y no sé como pasar props de hijo a padre (App.js) para luego pasarselo a (Characters.jsx).
¿Alguno sabe?

Así quedó:

Cree un componente “Charater”, me parece que se ve mejor así:
characters.jsx:

import React, { useState, useEffect } from "react";
import Character from './Character'
import './style/characters.css'

const Characters = () => {
  const [characters, setCharacters] = useState([]);

  useEffect(() => {
    fetch("https://rickandmortyapi.com/api/character/")
      .then((res) => res.json())
      .then((data) => setCharacters(data.results));
  }, []);

  return (
    <div className="characters">
      {characters.map((character) => {
       return <Character
                name={character.name}
                status={character.status}
                img={character.image}
                key={character.id}
                />;
      })}
    </div>
  );
};

export default Characters;

Character.jsx:

import React from 'react'
import './style/character.css'

const Character = ({name,status,img}) => {

    return (
        <div className="character_container">
            <img src={img} alt=""/>
            <div className="character_data">
                <h2>{name}</h2>
                <h2>{status}</h2>
            </div>
        </div>
    )
}

export default Character

Este fue mi resultado:

DarkMode:

HOLA!!!
aquí les dejo mi solución al reto 💚:


async/await

  const API =
  'https://rickandmortyapi.com/api/character'

  const getCharacters = async () => {
    const res = await fetch(API)
    const { results } = await res.json()
    setCharacters(results)
  }

  useEffect(() => {
    getCharacters()
  }, [])


Aquí está mi version usando la api de rick y morty e implementando el dark mode

les comparto mi template lo realice lo mejor que pude!!!


Esta sencillo el diseño y me inspire de dribbble

Yo solucione el reto asi:

    function cambioFondos(status) {
        const back = document.querySelector('.App')
        back.style.backgroundColor=status?'#000':'#fff';
        const header = document.querySelector('.header');
        header.style.backgroundColor=status?'#fff':'rgb(0, 128, 255)';
    }

Y la llamamos en el onclick asi:

    const handleClick = () =>{
        setDarkMode(!darkMode)
        cambioFondos(darkMode)
    }

Espero y les sirva

Seguimos en el proceso de aprendizaje! ♥

Usando async/await en el useEffect, para que el código luzca más elegante:

    useEffect(() =>{
        const fetchData = async () => {
            const response = await fetch(API_URL).then(res => res.json());
            setCharacters(response.results);
        }
        fetchData();
    }, []);

Dark Mode

LIght Mode

Sobre useEffect



Cuando investiguen sobre el hook useEffect se van a encontrar que se puede retornar una función para limpiar el efecto.

Esto se refiere a las accion asincronas que modificaran el estado una vez se hayan completado. Si un componente fue destruido antes de que la accion termine. Cuando lo haga tratara de renderizar en un componente que ya no existe por lo que podria dar problemas de rendimiento

En el caso de fetch y axios utiliza un objecto llamado AbortController que abortara la peticion http que se este haciendo cuando el componente se desmonte.

reto:

App.js

import React, { useState } from 'react';
import './App.css';
import Header from './components/Header/Header';
import { Characters } from './components/Characters/Characters';

function App() {
	const [darkMode, setDarkMode] = useState(false);
	const changeMode = () => {
		if (darkMode) {
			document.body.classList.add('lightMode');
			document.body.classList.remove('darkMode');
		} else {
			document.body.classList.add('darkMode');
			document.body.classList.remove('lightMode');
		}
	};
	return (
		<div>
			<Header
				darkMode={darkMode}
				setDarkMode={setDarkMode}
				changeMode={changeMode}
			/>
			<Characters />
		</div>
	);
}

export default App;

App.css

*,
*::before,
*::after {
	margin: 0;
	padding: 0;
	box-sizing: border-box;
}

html {
	font-size: 62.5%;
}

.darkMode {
	background-color: #333;
}

.lightMode {
	background-color: #eee;
}

Header.jsx

import React, { useState } from 'react';
import './header.css';

const Header = props => {
	const { darkMode, setDarkMode, changeMode } = props;
	const handleClick = () => {
		changeMode();
		setDarkMode(!darkMode);
	};

	return (
		<div className='header'>
			<h1>Rick & Morty Page</h1>
			<button type='button' onClick={handleClick}>
				{darkMode ? 'light Mode' : 'Dark Mode'}
			</button>
		</div>
	);
};

export default Header;

RETO
Ligth Mode

DarkMode

Para habilitar el emmet para JSX:
Abrir la configuración de VSCode: Command + , ó Ctrl + ,

asi me quedo el retoo uffff 💪

Tarde pero seguro:

Hice lo mejor que pude


Mi Reto!

Dark - Light. Eh!

Mi tarea:

Muy básico pero funciona.

Este ejercicio me gustó mucho.
|

|

Así quedó usando tailwind

https://jejorm.github.io/react-rick-morty/

Reto cumplido Oscar.

Light Mode.

Dark Mode

Si quieren revvisar mas a fondo este hook, incluso comparan ciertas configuración para replicar los ciclos de vida de un componente:
https://youtu.be/0ZJgIjIuY7U

Aqui mis resultados!
////////////////
Light Mode
/////////////////

//////////////////
Dark Mode
/////////////////

React lo mejor de lo mejor…

Mode Light

Mode Dark

Mi versión de #Reto 😃

Les dejo mi versión aquí.

#Reto

useEffect con async

...

//estado del componente
const [ characters, setCharacters ] = useState([])

// llamado a la API con useEffect
useEffect( ( ) => {
// arrow function con async
const getCharacters = async () => {
//llamado a la API con FECTH API
	const res = await Fecth('url_api')
// desestructuro results del objeto devuelto por la API y lo transformo en JSON
	const { results } = await res.json()
// actualizo el estado 
	setCharacters(results)
}
// llamado de la function parallamar a la API
getCharacters()

}, [ ]) // Solo 1 llamado a la API después del  primer render)

Reto

Soy muy malo diseñando 😅

Hice el reto usando useState, useContext, useEffect y variables de css.

Aun estoy pensando en los colores del dark theme 😁

Algo muy importante a destacar en useEffect es sus segundo argumento. Un arreglo de dependencias que controlan cuando debería ser ejecutado.

Las dependencias son valores definidos fuera del Hook pero son utilizados dentro.

Cabe resaltar que el segundo argumento es opcional y depende su uso React ejecutara el useEffect.

  1. Si no se le pasa un arreglo. React ejecutara el useEffect en cada render.
  2. Un arreglo vacio: React ejecutara el useEffect solo una vez
  3. Un arreglo con dependencias: React compara e valor actual de la dependencia con el valor que tenia antes de hacer el render. Si el valor no coincide entonces el useEffect vuelve a ejecutarse.

Recomiendo las siguentes lecturas sobre diferencias con el componentDidMount y el infinite-loop

para quitar los Warning de la consola debes agregarle un return al useEffect

 useEffect(() => {
    fetch('https://rickandmortyapi.com/api/character/')
    .then(response => response.json())
    .then(data => setCharacteres(data.results))
    return
  }, [])

y como hicimos un map agregarle el key

 return (
    <div className="characteres" key="index">
      {characters.map(character => (
        <h2>{character.name}</h2>
      ))}
    </div>
  );

Me gustaría mucho que explicaran por que es buena practica usar return en el useEffect

Yo empece a implementar los stylesd-components, una manera práctica y rapida de dar estilos en React
![](

![](

asi me quedo el codigo

App.js

import React from 'react';
import Header from './components/Header';
import Characters from './components/Characters';
import useDarkMode from './Hooks/useDarkMode';

import './App.css';

function App() {
  const [darkMode, setDarkMode] = useDarkMode();
  return (
    <div className="App"  style={darkMode? {backgroundColor: 'black', color: 'white'} : {backgroundColor: 'white'}}>
      <Header darkMode={darkMode} setDarkMode={setDarkMode}/>
      <Characters darkMode={darkMode} />
    </div>
  );
}

export default App;

Cree un Hook para manejar el Darkmode

import React, { useState } from 'react';

function useDarkMode() {
  const [darkMode, setDarkMode] = useState(false);

  return [darkMode, setDarkMode];
}

export default useDarkMode;

Characters.jsx

import React, {useState, useEffect} from 'react';
import styled from 'styled-components';

const Container = styled.div`
  background-color: ${props => props.darkMode ? 'black' : 'white'};
  color: ${props => props.darkMode ? 'white' : 'black'};
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 20px;
  margin: 10px;

`
const Card = styled.div`
  height: 100%;
  box-shadow: 2px 6px 8px rgba(0,0,0,0.19);
  border-radius: 8px;

  img {
    width: 100%;
    border-radius: 8px;
  }

  h2,h4 {
    margin: 0;
    margin-bottom: 4px;
  }
`

const Characters = ({darkMode}) => {
  const [characters, setCharacters] = useState([]);

  useEffect(() => {
    fetch('https://rickandmortyapi.com/api/character/')
      .then(response => response.json())
      .then(data => setCharacters(data.results))
  }, []);

  return (
    <Container darkMode={darkMode}>
    {
    characters.map(character => (
      <Card >
        <img src={character.image} alt={character.name} />
        <div>
          <h2>{character.name}</h2>
          <h4>{character.status}</h4>
          <h4>{character.species}</h4>
          <h4>{character.gender}</h4>
        </div>
      </Card>
    ))
    }
    </Container>
  )
}

export default Characters;

Header.jsx

import React, { useState } from 'react';
import '../styles/Header.css';


const Header = ({darkMode, setDarkMode}) => {
  const handleClick = () => {
    setDarkMode(!darkMode);
  }

  return (
    <div className="Header" style={darkMode? {backgroundColor: 'black', color: 'white'} : {backgroundColor: 'white'}}>
      <h1>ReactHooks</h1>
      <button
        style={darkMode? {color: 'white'} : null}
        type="button"
        onClick={handleClick}>
        {darkMode? 'Dark Mode' : 'Light Mode'}
      </button>
    </div>
  )
}

export default Header;

algo de estilo en styles/Header.css

.Header {
  display: flex;
  justify-content: space-evenly;
}
.Header button {
  background-color: transparent;
  margin: auto 0;
  height: 40px;
  width: 120px;
  font-size: 15px;
  font-weight: bold;
}

React.UseEffect
Ejecuta el código que tengamos adentro justo antes de que React tiene todo listo para renderizar el componente

  • El segundo argumento que le enviamos al hook puede ser un array vacío [ ], este le dice al UseEffect que solo se ejecute la primera vez que el componente se renderize, cuando se rerenderize no se ejecutara. Si dejamos ese segundo argumento vacío, el hook se ejecutara todas las veces que nuestro componente se rerenderize.
  • Podemos ejecutarlo cuando hayan cambios específicos en cierta variable o cierto componente, para eso podemos poner como segundo argumento un arreglo y adentro el nombre de la variable: [TotalToDos].

Creo que es recomendable no escribir la logica de llamado a la api dentro del useeffect, habria que llamar a una función que se encargue de eso.

Disfrutando y aprendiendo hooks! Me encanta que despues de las lecciones hay mini challenges!

import React, { useState, useEffect } from 'react'

const Characters = () => {
    const [characters, setCharacters] = useState([]);

    useEffect(() => {
        fetch("https://rickandmortyapi.com/api/character/")
        .then(response => response.json())
        .then(data => setCharacters(data.results))

    },[]);
 

    return (
        <div className="container mt-5">
            <div className="row">
            {characters.map(character => (
                <>
                <div className="col-4 mb-5">
                <div className="border border-dark p-3">
                    <img src={ character.image } alt="" />
                    <h4>{ character.name }</h4>
                    <h6>{ character.status } - { character.species }<small> ({ character.gender }) </small></h6>
                </div>
                </div>
                </>
            ))}
            </div>
        </div>
    )
}

export default Characters

Reto cumplido