PROJETO TODOLIST
PROJETO TODOLIST
Para configuração do gerenciador de estado, criei uma typagem para o formato do meu gancho com métodos e com isso, para criação do gancho é necessário a importação do create vindo do zustand.
export interface Task {
id: string
name: string;
marked: boolean;
}
interface StateTask {
tasks: Task[];
addTask: (task: Task) => void;
getTask: (taskName: string) => boolean;
markedTask: (id: string) => void;
getAmountTasksChecked: () => number;
getAmountTasksPending: () => number;
}
import { create } from 'zustand';
Dessa forma, basta criar o hook store function para criação do seu gancho, eu chamei ele de useTaskStore. Como o create recebe um generic do typescript, é possível passar o StateTask para o create. Dessa forma, o typescript já identifica o que é necessário dentro do meu gancho e as informações de retornos para as funções.
const useTaskStore = create<StateTask>((set, get) => ({
tasks: [],
addTask: (task: Task) => {},
getTask: (taskName: string) => {},
markedTask: (id: string) => {},
getAmountTasksChecked: () => {},
getAmountTasksPending: () => {}
}))
A função create recebe como parêmetro set e get, que são métodos para atualizar estado e recuperar alguma informação do estado, respectivamente.
Portanto, cada função exerce seu papel para modificar o estado ou recuperar alguma informação dele.
Os métodos getAmountTasksChecked e getAmountTasksPending recuperam as quantidade de tarefas checadas e tarefas que estão pendendes.
getAmountTasksChecked: () => number;
getAmountTasksPending: () => number;
Então, basta invocar elas no componente que chamei de AmounTasks.
export function AmountTasks() {
const { getAmountTasksChecked, getAmountTasksPending } = useTaskStore(state => state)
return (
<div className="flex gap-8">
<span className="text-3xl font-bold">Tasks: <span className="text-rose-500">{getAmountTasksPending()}</span></span>
<span className="text-3xl font-bold">Marked: <span className="text-rose-500">{getAmountTasksChecked()}</span></span>
</div>
)
}
A cada adição de tarefa, os componentes são renderizados novamente com novos valores atualizados, sem a utilização de providers. O zustand é possível integrar com fetch api para guardar uma informação vinda de alguma requisição, ou ate mesmo, compor o funcionamento da maneira que quiser, com Middleware.
Meu arquivo principal App, que engloba todos os componentes, possui o estado principal para renderização das tasks persistentes.
function App() {
const tasks = useTaskStore(state => state.tasks)
return (
<div className="w-screen h-screen flex flex-col gap-7 justify-center items-center">
<Logo />
<NewTask />
<form className="flex flex-col gap-3">
{tasks.map((task) => {
return (
<Task
key={task.id}
checked={task.marked}
id={task.id}
label={task.name}
/>
)
})}
</form>
<AmountTasks />
</div>
)
}
Cada componente Task possui uma função chamada toggleCheckTask, que recebe como parâmetro o ID da task selecionada. Dessa forma, a função vinda do useTaskStore, chamada de markedTask marca a aquela task como satisfeita ou selecionada. Com isso, atualizando o estado tasks.
export function Task({ checked, label, id }: TaskProps) {
const { markedTask } = useTaskStore();
function toggleCheckTask(taskId: string) {
markedTask(taskId)
}
return (
<CheckBox.Root
id={`checkbox-${id}`}
className="flex items-center gap-3 group"
checked={checked}
onCheckedChange={() => toggleCheckTask(id)}
>
<div className="h-6 w-6 rounded-lg flex items-center justify-center border-2 border-white group-data-[state=checked]:bg-rose-500 group-data-[state=checked]:border-rose-500 transition-colors group-focus:ring-2 group-focus:ring-rose-500 group-focus:ring-offset-2 group-focus:ring-offset-background">
<CheckBox.CheckboxIndicator>
<CheckIcon />
</CheckBox.CheckboxIndicator>
</div>
<label htmlFor={`checkbox-${id}`} className="font-bold text-lg group-data-[state=checked]:line-through group-data-[state=checked]:opacity-70">
{label}
</label>
</CheckBox.Root>
)
}