Solucionado (ver solução)
Solucionado
(ver solução)
4
respostas

Código alternativo: busca, filtro e ordenamento =)

Buenas galera!

Procurei me desafiar e desenvolver as funcionalidades de busca, filtro por categoria e ordenamento antes de assistir à essas aulas e... deu certo! Depois, assisti as aulas é claro, e verifiquei que o código/lógica utilizada pelo professor foi diferente (e de certa forma me parece mais correta pois trabalha o estado do componente). De qualquer maneira deixo abaixo o meu código do componente Itens > index.tsx.

Professor, qual seu feedback em relação à essa alternativa? É funcional e de qualidade também? Ou de fato é melhor trabalhar utilizando a lista a ser renderizada como estado do componente?

import foods from 'components/foods/foods.json' import styles from 'components/foods/Foods.module.scss' import Item from 'components/foods/item/Item'

interface Props { busca: string; filtro: number | null; ordenador: string }

interface Item { item: { title: string; description: string; photo: string; size: number; serving: number; price: number; id: number; category: { id: number; label: string; }; sortBy: () => void; } }

export default function Foods( {busca, filtro, ordenador }: Props ){ function sortBy(key: string) { return function(a: any, b: any){ if (a[key] > b[key]) { return 1; } if (a[key] < b[key]) { return -1; } // a must be equal to b return 0; } }

const buscadorFoods = foods.filter(
    (item) => (item.title.toLowerCase().indexOf(busca.toLowerCase()) > -1)
).sort(sortBy(ordenador))

const filtrosFoods = buscadorFoods.filter(
    (item) => item.category.id === filtro
).sort(sortBy(ordenador))

return(
    <div className={styles.itens}>
        {!filtro 
            ? buscadorFoods.map(item =>(<Item key={item.id} item={item}/>))
            : filtrosFoods.map(item=>(<Item key={item.id} item={item}/>))
        }
    </div>
)

}

4 respostas

Fala Xará, tranquilo?

Tem como tu me mandar o repositório no Github? aí eu consigo ter uma visão mais geral de como está o seu código e posso até fazer um Pull Request (com as sugestões de mudança) por lá mesmo, aí eu oficializo por aqui! O que acha?

Dalhe, claro!

Segue o repo do Github: https://github.com/luizfernandopezzi/irestaurant/

Mais especificamente, para o componente onde é renderizado os itens (chamei de Foods.tsx enquanto na aula chamamos de Itens.tsx): https://github.com/luizfernandopezzi/irestaurant/tree/master/src/components/foods

Obrigado!

solução!

Fala Xará, beleza?

Demorei mas voltei hahaha

Fiz um Pull Request no seu Github com algumas melhorias, você pode ver aqui

Antes de tudo, muito boa a sua ideia de manter os filtros fora de um estado até porque já temos o estado da lista dentro do json, então seria "uma duplicação" ter dois estados, mas como este curso era apenas uma introdução, achei esta forma para poder ensinar useState e useEffect de uma forma utilizável.

Como não estamos mais lidando mais com um estado, precisamos filtrar a lista toda a vez que o componente atualizar com alguma informação nova, e isto pode causar um problema de performance no futuro, pois se o ordenador mudar por exemplo, iremos calcular tudo novamente (tem isso no código original também, mas vou resolver isto agora).

Vou comentar aqui algumas coisas que eu fiz:

  • Você criou um filter para caso tenha um filtro e um para caso não tenha, mas isso não é necessário pois a gente consegue fazer tudo dentro do mesmo filter:
    const filteredFoods = useMemo(() =>
        foods.filter(item => {
            const matchSearch = handleMatchSearch(busca, item.title); // esta função verifica se o título corresponde a busca ou se a busca está vazia
            const matchFilter = handleMatchFilter(item.category.id, filtro) // esta função verifica se o título corresponde ao filtro ou se o filtro está vazio
            if (matchSearch && matchFilter) return true // coloca na lista se ele dá match na busca e no filtro
            return false;
        }, []), [busca, filtro]);

viu esse useMemo? Como você se esforçou para criar algo novo, eu vou te dar um açúcar no seu código, usando este useMemo você consegue "memorizar" o valor dessa variável, ela aceita 2 parâmetros, o primeiro é uma função que retorna o valor da variável (que você vai usar com o filteredFoods no caso) e o segundo parâmetros é um array de dependências, e a função do primeiro parâmetro só vai atualizar quando alguma variável do array mudar, maneiro né? o useMemo é um ótimo meio de evitar cálculos desnecessários, e nesse caso a gente só atualiza o filteredFoods quando a busca ou o filtro mudarem!

tá, mas e o ordenador? onde fica?

const sortedFoods = useMemo(() => filteredFoods.sort(sortBy(ordenador)),[ordenador, filteredFoods]);

Conseguimos criar aqui 2 variáveis, a filteredFoods que só atualiza quando o busca ou o filtro mudam e um sortedFoods que só muda quando o ordenador ou o próprio filteredFoods muda, agora temos estes códigos sendo atualizados só quando a gente realmente precisa!

agora o seu return ficou assim:

<div className={styles.itens}>
            {sortedFoods.map(item => (
                <Item
                    key={item.id}
                    item={item}
                />
            ))}
</div>

bem mais fácil de entender né?

  • Uma coisa interessante também é que você colocou algumas funções dentro do componente, e uma dica que eu te dou é, caso você não esteja utilizando algo de dentro do componente diretamente, coloque a função fora do componente. Isto faz com que sempre que o componente atualizar ele não precise criar a função novamente toda vez, sacou? Se você entrar no PR tem como ver sutilmente as funções fora do componente, e isto na prática ajuda bastante. Caso você queira colocar uma função dentro do componente que faça algo muito custoso, coloque ele dentro de um useCallback, que tem a mesma função do useMemo, só que para funções.

  • Seu código estava com um any dentro do seu sort dentro de Foods, e os 2 valores que são comparados são itens dentro de Foods, certo? Eu chamei este item de Food e criei um type pra ele dentro de src/types/Food.ts para poder reutilizar ele em vários lugares (este conceito da pasta types vai ser usado no próximo curso sobre react-router), e ficou assim:

export type Food = {
  title: string;
  description: string;
  photo: string;
  size: number;
  serving: number;
  price: number;
  id: number;
  category: {
      id: number;
      label: string;
  }
}

a tipagem do seu Item ficou assim:

interface Props {
    item: Food
}

e o seu sort dentro de Foods ficou assim:

function sortBy(key: string) {
    return (a: Food, b: Food) => (
        a[key as keyof Food] > b[key as keyof Food] ? 1 : -1
    )
}

Neste caso, não é necessário retornar 0, apenas 1 e -1 e o ternário é um ótimo candidato para não precisar ter um código muito grande.

Este [key as keyof Food] é uma forma que a gente consegue utilizar o Typescript para forçar um tipo, o as é a nomenclatura para forçar este tipo, keyof é uma forma de dizer que é algum key de algum objeto, e o objeto que a gente passa é Food, traduzindo fica literalmente key como uma key de Food.

Caso você tenha mais alguma dúvida, deixe aqui para a gente discutir beleza?

Bons estudos!

Tooooooop demais!

Obrigado!