隆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

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:

1D
4H
42M
55S

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

4/45
Recursos

Aportes 149

Preguntas 14

Ordenar por:

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

o inicia sesi贸n.

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 鈥淐harater鈥, 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

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

Hola les comparto mi solici贸n

El codigo seria este

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

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

export default App;
import React, { useEffect, useState } from 'react'
import hook from '../assets/hook.svg'
import titulo from '../assets/titulo.png'

const Header = () => {

   const [darkmode, setDarkmode] = useState(false)

   const handleDarkMode = () => {

      setDarkmode(!darkmode)

   }

   useEffect(() => {

      document.documentElement.style.setProperty("--primary", `${darkmode ? '#fff ' : 'rgb(32, 35, 41)'}`)
      document.documentElement.style.setProperty("--fondo", `${darkmode ? 'rgb(32, 35, 41)' : '#fff'}`)

   }, [darkmode, setDarkmode])

   return (
      <div className="Header">
         <div className="Header__titulo">
            ReactHook <img src={hook} alt="hook" />
         </div>

         <div className="Header__rickmorty">
            <img src={titulo} alt="" />
         </div>

         <div className="Header__darkmode">
            <button
               onClick={handleDarkMode}
               style={{
                  backgroundColor: darkmode ? '#477385' : '#fff',
                  color: darkmode ? '#fff' : '#477385',
               }}
            >
               {(darkmode) ?
                  (<i className="fa fa-moon-o" aria-hidden="true"></i>) :
                  (<i className="fa fa-sun-o" aria-hidden="true"></i>)}

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

export default Header

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

const Characters = () => {


   const [characters, setCharacters] = useState([])

   useEffect(() => {

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

   }, [])

   const statusCharacter = (status) => {
      switch (status) {
         case 'Dead':
            return 'muerto'

         case 'unknown':
            return 'desconocido'

         default:
            return 'vivo'
      }
   }

   return (
      <div className="Personajes">
         {characters.map(character => (
            <div className="Personajes__item animate__animated animate__fadeIn" key={character.name}>
               <div className="Personajes__imagen">
                  <img src={character.image} alt={character.name} />
               </div>
               <div className="Personajes__info">
                  <p className="nombre"> <strong>{character.name}</strong></p>
                  <p className="nombre"> <strong>{character.species}</strong></p>
                  <p className="nombre"> <strong>{character.gender}</strong></p>
                  <p className="nombre"> <strong>{character.status}</strong> <span className={`estado ${statusCharacter(character.status)}`}></span> </p>
               </div>
            </div>
         ))}
      </div>
   )
}

export default Characters

El css:

index.js

:root{
  --fondo:#fff;
  --primary:rgb(32, 35, 41);
}
*{
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  background-color: var(--fondo);
  height: 100vh;
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
    sans-serif;
    /* font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

App.css

.App {
  text-align: center;
  padding: 15px 20px 0 20px;
}

.App-logo {
  height: 40vmin;
  pointer-events: none;
}

.Header{
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-bottom: 15px;
}

.Header__titulo{
  font-weight: bold;
  display: flex;
  align-items: center;
  font-size: 20px;
  color: var(--primary);
 
}

.Header__titulo img{
  width: 30px;
  margin-left: 0px;
}

.Header__rickmorty img{
  width: 250px;
}

.Header__darkmode button{
  border: none;
  outline: none;
  width: 50px;
  height: 50px;
  border-radius: 50%;
  cursor: pointer;
  font-weight: 900;
  font-size: 25px;
  color: #477385;
  background-color: #fff;
  border: 2px solid #477385;
  transition: all .3s;
}

.Personajes{
  padding: 30px 0;
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
  justify-content: center;
}

.Personajes__item{
  width: 240px;
  box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
  border-radius: 7px;
  overflow: hidden;
  background-color: #fff;
}

.Personajes__info{
  padding: 20px;
  
}

.Personajes__item img{
  width: 100%;
  display: flex;
}

.Personajes__info p{
  color: rgb(158, 158, 158);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
}

.Personajes__info p strong{
  color: rgb(32, 35, 41);
}

.Personajes__info .estado{
  width: 6px;
  height: 6px;
  
  border-radius: 50%;
  line-height: 0;
}

.Personajes__info .estado.vivo{
  background-color: rgb(85, 204, 68);
}

.Personajes__info .estado.muerto{
  background-color: rgb(214, 61, 46);
}

.Personajes__info .estado.desconocido{
  background-color: rgb(158, 158, 158);
}

useEffect se puede usar para peticiones, funciones que funcionen asyncronamente, llamados a API !! 馃槃

Recordemos que useEffect empieza a trabajar una vez el componente empiece a ser renderizado. Cada vez que se llame el componente se estara haciendo paralelamente la peticion a la api. o lo que sea que hagamos dentro del useEffect

Mi reto cumplido馃槑馃槑