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!