Introducci贸n al curso avanzado de React

1

Qu茅 necesitas para este curso y qu茅 aprender谩s sobre React.js

2

Proyecto y tecnolog铆as que usaremos

Preparando el entorno de desarrollo

3

Clonando el repositorio e instalando Webpack

4

Instalaci贸n de React y Babel

5

Zeit es ahora Vercel

6

Linter, extensiones y deploy con Now

Creando la interfaz con styled-components

7

驴Qu茅 es CSS-in-JS?

8

Creando nuestro primer componente: Category

9

Creando ListOfCategories y estilos globales

10

Usar informaci贸n real de las categor铆as

11

Creando PhotoCard y usando react-icon

12

SVGR: de SVG a componente de ReactJS

13

Creando animaciones con keyframes

Hooks

14

驴Qu茅 son los Hooks?

15

useEffect: limpiando eventos

16

useCategoriesData

17

Usando Intersection Observer

18

Uso de polyfill de Intersection Observer e imports din谩micos

19

Usando el localStorage para guardar los likes

20

Custom Hooks: useNearScreen y useLocalStorage

GraphQL y React Apollo

21

驴Qu茅 es GraphQL y React Apollo? Inicializando React Apollo Client y primer HoC

22

Par谩metros para un query con GraphQL

23

Usar render Props para recuperar una foto

24

Refactorizando y usando variables de loading y error

25

Usando las mutaciones con los likes

Reach Router

26

驴Qu茅 es Reach Router? Creando la ruta Home

27

Usando Link para evitar recargar la p谩gina

28

Creando la p谩gina Detail

29

Agregando un NavBar a nuestra app

30

Estilando las p谩ginas activas

31

Rutas protegidas

Gesti贸n del usuario

32

Introducci贸n a React.Context

33

Creaci贸n del componente UserForm; y Hook useInputValue

34

Estilando el formulario

35

Mutaciones para registro

36

Controlar estado de carga y error al registrar un usuario

37

Mutaciones para iniciar sesi贸n

38

Persistiendo datos en Session Storage

39

Hacer like como usuario registrado

40

Mostrar favoritos y solucionar fetch policy

41

Cerrar sesi贸n

Mejores pr谩cticas, SEO y recomendaciones

42

脷ltimos retoques a las rutas de nuestra aplicaci贸n

43

React Helmet

44

Midiendo el performance de nuestra app y usando React.memo()

45

React.lazy() y componente Suspense

46

Usando PropTypes para validar las props

47

PWA: generando el manifest

48

PWA: soporte offline

49

Testing con Cypress

Conclusiones

50

隆Felicidades!

No tienes acceso a esta clase

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

Curso de React Avanzado

Curso de React Avanzado

Miguel 脕ngel Dur谩n

Miguel 脕ngel Dur谩n

useEffect: limpiando eventos

15/50
Recursos

Aportes 73

Preguntas 12

Ordenar por:

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

o inicia sesi贸n.

Les dejo un art铆culo que escrib铆 sobre el hook useEffect por si les puede ayudar a complementar esta clase: https://midu.dev/react-hooks-use-effect-funcionalidad-en-el-ciclo-vida-componentes/

Yo en vez de hacer un fadeIn hice que se mostrara desde arriba. Tambi茅n aprovech茅 la animaci贸n para no renderear el componente cada vez que el estadoshowFixed cambie si no que la animaci贸n se encargue de sacarlo del viewport.

Usando react spring 馃槢

un peque帽o shortcode para usar los Fragments de react es usar " <>" y 鈥</>鈥 para cerrar. No hace falta importar {Fragment} de react, ya que ya lo interpreta.

    <>
      {renderList()}
      {renderList(true)}
    </>

Les dejo esta animaci贸n de efecto rebote

const bounceDownKeyFrames = keyframes`
 0% {
    top: -70px;
  }

  25% {
    top: 0px;
  }

  40%{
    top: 10px
  }

  65%{
    top: -3px
  }

  100% {
    top: 0px;
  }
`

export const bounceDown = ({ time = '1s', type = 'ease' } = {}) =>
  css`
    animation: ${time} ${bounceDownKeyFrames} ${type};
  `

Solo agregue la funcion de fadeIn en styles de la lista, para cuando es fixed:

import styled from 'styled-components'
import { fadeIn } from '../../styles/animation'

export const List = styled.ul`
  display: flex;
  overflow: scroll;
  width: 100%;
  &.fixed {
    ${fadeIn()};
    background-color: #fff;
    border-radius: 60px;
    box-shadow: 0 0 20px rgba(0, 0, 0, 0.3);
    left: 0;
    margin: 0 auto;
    max-width: 400px;
    padding: 5px;
    position: fixed;
    right: 0;
    top: -20px;
    transform: scale(.5);
    z-index: 1;
  }
`

export const Item = styled.li`
  padding: 0 8px;
`

Lista fija de categor铆as con la animaci贸n fadeIn que hab铆amos hecho:

hasta ahora pensaba que solo pod铆a usar usar useEfect una sola vez en un componente 馃く馃く馃く

Con algunos comentarios de como entend铆:

import React, { Fragment, useEffect, useState } from "react";
import { Category } from "../Category/Category";
import { List, Item } from "./styles";

export const ListOfCategories = () => {

  /* setear el estado inicial */
  const [categories, setCategories] = useState([]);
  const [showFixed, setShowFixed] = useState(false);

  /* useEffect se ejecuta cada vez que se renderiza el componente */

  /* useEffect para obtener los datos del API */
  useEffect(function () {
    window
      .fetch("http://localhost:3000/categories")
      .then((res) => res.json())
      .then((response) => {
        setCategories(response);
      });
  }, []);


  /* useEffect para mostrar las categorias cuando el scroll baje */
  useEffect(function () {

    /* Funci贸n onScroll para verificar el movimiento del scroll */
    const onScroll = e => {
      /* si el scroll  es en Y es mayor a 200 entones newShowFixed == true */
      const newShowFixed = window.scrollY > 200

      /* si el */
      showFixed !== newShowFixed && setShowFixed(newShowFixed)
    }

    /* Escuchar el movimiento del scroll, se suscribe un evento. */
    document.addEventListener('scroll', onScroll)
    console.log(showFixed);

    /* cuando se desmonta el componente se elimina la suscripci贸n al evento */
    return () => document.removeEventListener('scroll', onScroll)

  }, [showFixed])


  const renderList = (fixed) => (
    <List className={fixed ? 'fixed' : ''}>
      {categories.map((category) => (
        <Item key={category.id}>
          <Category {...category} />
        </Item>
      ))}
    </List>
  )
  return (
    <Fragment>
      {renderList()}
      {showFixed && renderList(true)}
    </Fragment>

  );
};

Mi propuesta para hacer el efecto de las categorias con IntersectionObserver 馃馃馃:

Yo use una animaci贸n para cambiar el scale, dejo el snippet por si alguien quiere probarlo.

const scaleDown = keyframes`
    from {
      transform: scale(1);
    }
    to {
      transform: scale(0.5);
    }
`;
const scale = ({time = "1s", type = "ease"} = {}) => css`animation: ${time} ${scaleDown} ${type}`;

const Ul = styled.ul`
  display: flex;
  overflow: scroll;
  width: 100%;
  ${props => props.fixed && css`
    background: #ffffff;
    border-radius: 60px;
    box-shadow: 0 0 20px rgba(0, 0, 0, 0.3);
    left: 0;
    margin: 0 auto;
    max-width: 500px;
    padding: 5px;
    position: fixed;
    right: 0;
    top: -20;
    transform: scale(0.5);
    ${scale}
    z-index: 1;
  `}
`;

Excelente鈥

Ac谩 mi animaci贸n:


const positionDownKeyFrames = keyframes`
    0%{
      margin-top:-100px;
    }

    100%{
      margin-top:0;

    }
`
export const positionDown = ({ time = '1s', type = 'ease' } = {}) =>
  css`animation: ${time} ${positionDownKeyFrames} ${type}`
Me parece que este problema se hubiese solucionado con la propiedad "sticky" de css. Aunque esta clase sirvi贸 para aprender otras cosas interesantes, pero estar铆a bueno haber dejado claro eso.

De esta manera hice el efecto (con una ternary):

useEffect(function () {
    function onScroll (e) {
      window.scrollY > 200
        ? setShowFixed(true)
        : setShowFixed(false)
    }

    document.addEventListener('scroll', onScroll)

    return function () {
      document.removeEventListener('scroll', onScroll)
    }
  }, [showFixed])

una lectura para entender mas de useEffect
useEffect en el ciclo de vida de componentes

no se si a alguien mas le paso, pero si no les sale la renderList(fixed) coloquenla antes que la renderList()

<>
{renderList(true)}
{renderList()}
</>

hola !
la url ("https://petgram-server.midudev.now.sh/categories") para obtner las cetegorias esta devolviendo un 502

Aqui esta mi animacion espero les guste

Para los que viene de los cursos de oscar 馃槢 tambien podiamos indicar los fragment de esta manera 鈥渃orta鈥 <> </>

  return (
    <>
      {renderList()}
      {showFixed && renderList(true)}
    </>
  )

驴Es necesario usar doble llamado a la funci贸n renderList? 驴No es suficiente con algo as铆?

renderList(showFixed)

me surge una duda

const renderList = () => { ... }

no termina creando una nueva funci贸n en cada render del componente? o es algo por lo que no deber铆a de preocuparme?

Cada vez voy notando el poder de utilizar styled-components en nuestros proyectos, incluso lo podemos usar para condicionar nuestro estado, excelente herramienta. 馃殌鈥

Incre铆ble 馃槺, llevo varios proyectos incorporando reactHooksy nunca se me hab铆a pasada por la cabeza hacer m谩s de un useState, me acostumbre a resalizar solo 1 componentDidMount, pero me doy cuenta que el useState combina los poderes del componentDidUpdateen el array que recibe como segunda par谩metro, es incre铆ble, ahora mis aplicaciones tendr谩n un mejor rendimiento. 馃槃

Puedes describir como hacer un correcta estructura de archivos y carpeta para un proyecto?

Implementaci贸n del efecto fadeIn en la lista de categorias

import styled from 'styled-components'
import { fadeIn } from '../../styles/animation'

const List = styled.ul`
  display: flex;
  overflow-x: auto;
  width: 100%;
  &.fixed {
    ${fadeIn({ time: '0.8s', type: 'ease-in-out' })}
    background: #fff;
    border-radius: 60px;
    box-shadow: 0 0 20px rgba(0, 0, 0, 0.3);
    left: 0;
    margin: 0 auto;
    max-width: 400px;
    padding: 5px;
    position: fixed;
    right: 0;
    top: -20px;
    transform: scale(0.5);
    z-index: 1;
  }
`

const Item = styled.li`
  padding: 0 8px;
`

export { List, Item }
mm me parece que useffect donde se setea el listener de scroll, no deber铆a tener ninguna dependencia, ya que se debe ejecutar solo la primera vez que se renderiza el componente, no? No tiene sentido que se vuelva a ejecutar cada vez que se renderiza, ya que el callback "onScroll" se encarga de eso

Usando react-top-loading-bar

Mi animaci贸n

Code:
animation.js

import styled, { css, keyframes } from "styled-components";

const scale = keyframes`
from {
  transform: scale(1);
  top: -100px;
  border-radius: 2px;
}
to{
  transform: scale(.66);
  border-radius: 60px;
}
`
export const scaleDown = ({ time = "1s", type = "ease" } = {}) => css`
animation: ${time} ${scale} ${type};
`;

que gran curso! lastima que necesite actualizacion

Para el reto solo importamos en los styles:
import { fadeIn } from 鈥樷/鈥/styles/animation鈥

Luego agregamos: ${fadeIn()} cuando se haga el fixed.
&.fixed {
${fadeIn()}
.
.
.
}

Les dejo otra forma utilizando Logical Operators y un video de @Midudev explicando sobre el uso de ternarias: https://www.youtube.com/watch?v=YFES8Nm6uF4

<List className={fixed &&= 'fixed'}>
//Code
</List>

Ac谩 hay otra forma de hacer el toggle de las categor铆as:

  useEffect(function () {
    const onScroll = e => {
      window.scrollY > 200 ? setShowFixed(true) : setShowFixed(false)
    }
    document.addEventListener('scroll', onScroll)
  }, [])

Yo hice la comprobacion de esta manera para no hacer otra funcion

useEffect(() => {
    const handleScroll = () => {
      if (window.scrollY > 200) {
        setFixedCategory(true);
      } else {
        setFixedCategory(false);
      }
    };
    window.addEventListener("scroll", handleScroll);
    return () => {
      window.removeEventListener("scroll", handleScroll);
    };
  }, [fixedCategory]);

  return (
    <List className={fixedCategory ? "fixed" : null}>
      {categories?.map((category) => (
        <li key={category.id}>
          <Category {...category} />
        </li>
      ))}
    </List>
  );
};
export { ListOfCategories };

Hola!, el c贸digo en la descripcion de la clase aparece minificado. Al menos el index.js de ListOfCategories

Hola aqu铆 les dejo mi aporte:

No es malo estar agregando eventos en cada render de la app?

Asi me quedo a mi, el escrolleable era un objeto del dom y no el window

import React,{ useEffect, useState } from "react"
import   styled     from "styled-components"
import { Category } from "../Category"
import   db         from "../../backend/api/db.json"

/// if use trick declare object:  const renderList =(fixed, {delay: delay}=0 )=>
const renderList =(fixed, delay=0 )=>   {   return ( <>
  <List className={ fixed? 'fixed' : '' }>
    { db.categories.map( 
        cat=>
          <Item key={cat.id}> 
            <Category {...cat} delay={delay}/>
          </Item> 
      ) 
    }
  </List>
</>
)};

const ListOfCategories =()=>{ const [showFixed, setShowFixed ] = useState(false)

  useEffect(()=> {
    const cards = document.querySelector("#scrolleable");
    
    const onScroll = (cards=this.cards, e) =>{
      const newShowFixed = cards.scrollTop>100;
      showFixed !== newShowFixed && setShowFixed(newShowFixed);

    }; cards.addEventListener('scroll', ()=>onScroll(cards) );

    return ()=> cards.removeEventListener('scroll', onScroll);
  },[showFixed])
  
  return (
    <> 
      {renderList()}
      {showFixed && renderList(true)} 
      {/* {showFixed && renderList(true, {delay=10} )}  */} //!trick
    </> 
  ) 

}; export { ListOfCategories, renderList };

export const List = styled.section`
  display: flex;
  position: relative;
  z-index: 1;
  overflow: auto;
  width: 100%;
  height: 130px;
  ::-webkit-scrollbar {
    display: none;
  }
  &.fixed{
    border-radius: 1000px;
    box-shadow: 0 0 20px rgba(0,0,0,.40);
    position: sticky;
    top: -36px;
    right: 0;
    left: 0;
    margin: 0 auto;
    max-width: 400px;
    padding: 5px;
    transform: scale(.5);
    z-index: 13;
    backdrop-filter: blur(30px);
  }
`
export const Item = styled.article`
  padding: 0 8px;
`

ListOfCategories/index.js

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

import {List, Item} from './styles';

import { Category } from '../Category';

export const ListOfCategories = () => {
    const [categories, setCategories] = useState([]);

    const [showFixed, setShowFixed] = useState(false);

    //Show Categories fetching the data
    useEffect(function(){
        window.fetch('https://petgram-server-alejandroverita-alejandroverita.vercel.app/categories')
            .then(res => res.json())
            .then(data => {
                setCategories(data)
        })
    }, [])

    //Show categories when scroll is higher 200px
    useEffect(()=>{
        const onScroll = e => {
            const newShowFixed = window.scrollY > 200
            showFixed !== newShowFixed && setShowFixed(newShowFixed)
        }

        document.addEventListener('scroll', onScroll)

        //Avoid memoryLeak
        return () => document.removeEventListener('scroll', onScroll)
    }, [showFixed])

    const renderList = (fixed) => (
        <List className={fixed ? 'fixed' : ''}>
            {
                categories.map(category => 
                    <Item key = {category.id}>
                        <Category {...category} />
                    </Item>
                )
            }
        </List>
    )
    
    return (
        <>
            {renderList()}
            {showFixed && renderList(true)}
        </>
    )
}

ListOfCategories/styles.js

import styled from 'styled-components';
import {scale} from '../../Styles/animation';

export const List = styled.ul`
    display: flex;
    overflow: scroll;
    width: 100%;
    //desaparece el scroll sin perder la funcionalidad 
    &::-webkit-scrollbar {
        display: none;
    };
    &.fixed {
        background-color: white;
        border-radius: 60px;
        box-shadow: 0 0 20px rgba(0, 0, 0, 0.3);
        left: 0;
        margin: 0 auto;
        max-width: 400px;
        padding: 5px;
        position: fixed;
        right: 0;
        top: -20px;
        transform: scale(0.5);
        ${scale({time:'0.3s'})}
        z-index: 1;
    }

  `

export const Item = styled.li` 
    padding: 0 8px;
    list-style: none;
`

animation.js

import {keyframes, css} from 'styled-components';

const fadeInKeyframes = keyframes ` 
    from {
        filter: blur(5px);
        opacity: 0;
    }
    to {
        filter: blur(0);
        opacity: 1;
    }
`;

export const fadeIn = ({time = '1s', type='ease'} = {}) => css`
    animation: ${time} ${fadeInKeyframes} ${type};
`;



const scaleDown = keyframes`
    from {
      transform: scale(1);
    }
    to {
      transform: scale(0.5);
    }
`;

export const scale = ({time='1s', type='ease'} = {})=> css ` 
    animation: ${time} ${scaleDown} ${type};
`;

Para un mayor entendimiento del c贸digo, aconsejo sacar la funci贸n onScroll del useEffect鈥 porfas, si hacer esto est谩 mal, h谩ganmelo saber


  const onScroll = (e) => {
    const newShowFixed = window.scrollY > 200

compare with showFixed
    showFixed !== newShowFixed && setShowFixed(newShowFixed)
newShowFixed before is declarated
    console.log('adios:(')
  }

  useEffect(() => {
    document.addEventListener('scroll', onScroll)
    return () => {
      console.log('hola:)')
      document.removeEventListener('scroll', onScroll)
    }
  }, [showFixed])

Tenia problemas con ejecutar el listener y traer el valor de window.scrollY. No se ejecutaba ninguno de los dos. Leyendo me encontre con que en los estilos globales al id #app le estamos pasadano un height: 100vh. Una vez lo quit茅, me funciono correctamente la accion de lista de categorias. Alguien me puede explicar por que?

#app{
    box-shadow: 0 0 10px rgba(0,0,0,.05);
    overflow-x: hidden;
    //height: 100vh;  // si se le da esta propiedad, no se puede acceder a window.scrollY ni document.addEventListener('scroll'...
    padding-bottom: 10px;
  }

Genial

ni idea que existia transform: scale(.5); jajaj

Les comparto un proyecto que hice, consumiendo una API https://petlove-3sbf43kkw-montilva74.vercel.app/, no es perfecto pero me siento orgullosa de todo.

const onScroll = () => {
      window.scrollY > 200 ? setShowFixed(true) : setShowFixed(false);
    };

Muy interesante, muchas gracias!!

Lo que no entend铆 al principio era el llamado a Vercel, pero ya en materia s贸lo ten铆a que llamar a la api:

https://petgram-server-rsor.vercel.app/categories

Excelente, cosas que antes pensaba que eran tediosas de hacer en React ahora son simples.

Al crear la lista est谩tica esta se muestra debajo de la lista fhtoCard, 驴como puedo solucionarlo?

Lista de categorias con el efecto fadeIn
https://ibb.co/3Mcb1d6

http://platzi.com/comentario/660554/
Al darle scroll para mostrar la lista estatica en mi proyecto esta se muestra por debajo de la lista fhotocard

@midudev como puedo usar variables de elementos dentro de otro elemento? Te hago un ejemplo:

Para estilos de categorias

export const Anchor = styled.a`
  display: flex;
  flex-direction: column;
  text-align: center;
  text-decoration: none;
  width: 75px;
  &.fixed {
    width: 45px;
  }
`
export const Image = styled.img`
  border: 1px solid #ddd;
  box-shadow: 0px 1px 14px rgba(0, 0, 0, .2);
  border-radius: 50%;
  height: auto;
  overflow: hidden;
  object-fit: cover;
  height: 75px;
  width: 75px;
`

Y teniendo otro elemento que sea el contenedor de los otros dos, por ejemplo

export const CategoryContainer = styled.div`
  &.fixed {
    a {
      width: 45px;
    }

    img {
      width: 45px;
      height: 45px;
    }
  }
`

驴C贸mo puedo hacer para que en vez de utilizar a, img, utilizar las constantes asociadas a ese elemento? Es decir:

export const CategoryContainer = styled.div`
  &.fixed {
    Anchor {
      width: 45px;
    }

    Image {
      width: 45px;
      height: 45px;
    }
  }
`

驴Como puedo lograr algo similar?

Saludos Miguel, muy buen curso!.
Tengo una consulta: tengo un custom Hook llamado useFetch() que quiero usar como helper para todas las peticiones que necesite el sitio, el problema surge cuando lo quiero utilizar dentro de un useEffect, bien sea para una carga inicial o un pulling con interval, entiendo que es por las reglas de los Hooks.
La duda es, no es un caso correcto de use Hooks? es decir, debo reescribirlo como una funcion helper o estoy haciendo algo mal?
Muchas gracias.!

隆Geniaaal! Maravilloso efecto y super simple!
Solo tengo una duda y quiz谩 sea rid铆cula, pero a煤n as铆 no me privar茅 de expresarla @midudev 驴No hay problemas de performance al agregar el listener cada que se renderiza el componente? 驴O el browser se da cuenta que el listener en realidad no hay cambiado y lo gestiona?
Pero enserio me pareci贸 brutal lo que hiciste por que mi soluci贸n hubiese sido mucho m谩s compleja, 隆vivan los hooks!

Una pregunta, al desmontar el componente 驴Los addeventlisteners se borran?

import styled from 'styled-components';

import fadeIn from '../../styles/animation';

export const Anchor = styled.a`
  display: flex;
  flex-direction: column;
  text-align: center;
  text-decoration: none;
  width: 75px;
`;

export const Image = styled.img`
  ${fadeIn()}
  border: 1px solid #ddd;
  box-shadow: 0px 10px 14px rgba(0, 0, 0, .2);
  border-radius: 50%;
  height: auto;
  overflow: hidden;
  object-fit: cover;
  height: 75px;
  width: 75px;
`;

No se que tan buena sea mi soluci贸n, pero hice el reto agregando que se haga la animaci贸n cuando aparece y cuando desaparece la lista de categor铆as.

src/components/ListOfCategories/styles.js
agregue las animaciones
propiedad visibility
el transition
importo animaci贸n fadeOut
y la variable showOrHide que paso por las props

import { fadeIn, fadeOut } from '../../styles/animations'

export const List = styled.ul`
  display: flex;
  overflow: scroll;
  width: 100%;
  &.fixed{
    ${props => props.showOrHide ? fadeIn() : fadeOut()}
    visibility: ${props => props.showOrHide ? 'visible' : 'hidden'};
    background: #fff;
    border-radius: 60px;
    box-shadow: 0 0 20px rgba(0, 0, 0, 0.3);
    left: 0;
    margin: 0 auto;
    max-width: 400px;
    padding: 5px;
    position: fixed;
    right: 0;
    top: -20px;
    transform: scale(.5);
    z-index: 2;
    transition: visibility 1s;
  }
`

src/styles/animations.js
la animaci贸n fadeOut

const fadeOutKeyframes = keyframes`
  from{
    filter: blur(0);
    opacity: 1;
  }

  to {
    filter: blur(5px);
    opacity: 0;
  }
`
export const fadeOut = ({ time = '1s', type = 'ease' } = {}) =>
  css`animation: ${time} ${fadeOutKeyframes} ${type};`

src/components/ListOfCategories/index.js
siempre se renderizan las 2 listas de categor铆as
el estado showFixed lo paso al componente en la propiedad showOrHide

const renderList = (fixed) => {
    return (
      <List showOrHide={showFixed} className={fixed ? 'fixed' : ''}>
        {
          categories.map(category => <Item key={category.id}><Category {...category} /></Item>)
        }
      </List>
    )
  }

  return (
    <>
      {renderList()}
      {renderList(true)}
    </>
  )

esta parte esta bien interesante
https://petgram.flavs.now.sh/
aqui pueden ver mi resultado
solo agregue en:
&.fixed
${fadeIn()}
ease;
y queda ya que los estilos estan definidos

Puse el fadeIn antes de que lo dijera en el final 馃槸

Mi solucion:
src\components\ListOfCategories\Styles.js

import styled from 'styled-components'
import { fadeIn } from '../../Styles/animation'

export const List = styled.ul`
  display: flex;
  overflow: scroll;
  width: 100%;
  &::-webkit-scrollbar {
    display: none;
  }
  &.fixed {
    ${fadeIn({ time: '1s' })}
    background: #FFF;
    border-radius: 60px;
    box-shadow: 0 0 20px rgba(0, 0, 0, 0.3);
    left: 0;
    margin: 0 auto;
    max-width: 400px;
    padding: 5px;
    position: fixed;
    right: 0;
    top: -20px;
    transform: scale(0.5);
    z-index: 1;
  }
`
export const Item = styled.li`
  padding: 0 8px;
`

NO entendi esta parte

    document.addEventListener('scroll', onScroll)
    return () => document.removeEventListener('scroll', onScroll)
  }, [showFixed])```

no me qued贸 muy claro lo de las dependencias鈥 y en la documentaci贸n no lo encontr茅

Por fin pude entender useEffect! Muchas gracias!

Muy sencillo utilizar el fadeIn ya lo teniamos preparado para usar en cualquier otro .css

Custom Hooks
Son infinitos porque podemos crear nuestro propio custom hooks.
Podemos utilizar un hooks de forma que se pueda reutilizar la l贸gica en diferentes componentes. Otra ventaja es la separaci贸n de conceptos que nos permite separar diferentes conceptos en diferentes hooks, agrupando mejor que estamos haciendo en cada parte de nuestro c贸digo.
Son 100% retro compatibles, no tenemos que volver a escribir nuestro c贸digo para adaptarlo a los hooks pasamos progresivamente nuestra aplicaci贸n a utilizar hooks cuando tenga sentido.
Mejor transpilaci贸n con Babel. Mejor Performance, la ejecuci贸n de una funci贸n es m谩s r谩pida que evaluar una clase.

Dato curioso
Fragment se puede usar de 3 formas

React.Fragment //Usando React para acceder a esta propiedad 
Fragment //Importandolo
<></> //isin importar ni llamar por propiedad

Aplicar el efecto de fadeIn se puede hacer reutilizando la animaci贸n usada en las im谩genes de las cardas:

export const List = styled.ul`
  display: flex;
  overflow: scroll;
  width: 100%;
  &::-webkit-scrollbar {
    display: none;
  }
  &.fixed {
    ${fadeIn({time: '0.8s'})}
    background: white;
    border-radius: 60px;
    box-shadow: 0 0 20px rgba(0, 0, 0, 0.3);
    left: 0;
    margin: 0 auto;
    max-width: 400px;
    padding: 5px;
    position: fixed;
    right: 0;
    top: -20px;
    transform: scale(.5);
    z-index: 1;
  }
` ```

la animacion cuando aparezca el fixed primero en el styled List pongo esto

  ${({ fixed }) => fixed ? fadeIn() : ''};

luego le paso esa prop

<List fixed className={fixed ? 'fixed' : ''}>

Ya le voy agarrando cari帽o al useEffect, la aplicaci贸n va a al 100

Todav铆a no logro sacarle la barra de scroll a las categor铆as. Prob茅 con webkit y si lo saca pero el tema es que el mouse no escrolea horizontalmente. alguna sugerencia?

Hola, les dejo mi repositorio de este proyecto, pero hecho en Nextjs:

https://github.com/danyel117/petgram-platzi/tree/floating_categories

&.fixed{
	${fadeInd({ time: '2s', type: 'ease' })}
}

https://clonegram-client-epqhak6k4.now.sh/
dejar茅 esto por aqu铆 xd