logo
Guide

Hooks & Events

Continuing to work on now, let's add some states and get the pagination working! Import and at the top. And inside the function let's create some states:

const [page, setPage] = useState(0);
  const [slicedUsers, setSlicedUsers] = useState<User[]>([]);

The first state, , is just like a state we'd create with regular Javascript. The second one, is a little different and leverages Typescript's 'generics'. In typescript- you can create functions and interfaces that are 'generic'. That means they accept and utilize different types.

This is useful if we want to describe something and make it typesafe- but we'll be reusing it for multiple types. For example you may have API responses that always return some type of data in a nested array- but the rest of the response is always the same. You could build out a generic interface to handle all the responses:

interface APIResponse<T>{ // the T is the generic 'type'
	responseCode:number;
	date:string;
	referrer:string;
	data:T[];
}

You can then pass in different 'types' as and Typescript would know that the contains a responsecode, a date, a referrer, and an array of whatever type that you passed in was.

const responseForUsers:APIResponse<User> = await fetchUsers();
const responseForPosts:APIResponse<Post> = await fetchPosts();
... etc ...

In our case with our state, is a generic function. We can pass a type in useState<T>, and then typescript and our editor will know that our is an array of Users, and our , should set an array of Users.

Why didn't we have to do that with the other state called ? Just like with all types- you can be explicit or implicit. Because we passed a in to that state, it was implicitly set as a number type. But because we just passed an empty array to our initial state for , we had to explicitly tell typescript that this is actually supposed to be an array of type , we just don't quite have the exact data yet.

Generics are a pretty large topic, but a very powerful tool to understand. You should check the docs out and try to learn how to use them... but it's a little beyond the scope of a crash course like this.

Let's keep building out the pagination. We'll create a under our states that sets the value of our slicedUsers to sets of 5 based on the page we're on.

useEffect(() => {
    setSlicedUsers(users.slice(page * 5, page * 5 + 5));
  }, [page, users]);

This will run whenever we get our array from the props, and whenever the user clicks a button to change the . This is client-side pagination. We'll change our main to fetch all the pages at once, and then we'll control how many are shown with client-side logic.

Let's update our buttons in the pagination section. We want to add an onClick handler, and I'm going to add a 'data' attribute to the button that we can read in the handler. I like to do this to avoid creating anyonymous functions inside of a map.

{[...Array(5)].map((_, i) => (
            <button
              key={i}
              className="bg-gray-200 rounded-md px-2 py-1"
              data-page={i}
              onClick={pageClick}
            >
              {i + 1}
            </button>
          ))}

We can change our className to change the background color if this button is the current 'page' as well:

className={`${
                page === i ? "bg-gray-200" : "bg-slate-800"
              } rounded-md px-2 py-1`}

Now we'll make the pageClick function.

const pageClick = (e: React.MouseEvent<HTMLButtonElement>) => {
    const page = e.currentTarget.dataset.page;
    if (page) setPage(parseInt(page));
  };

Event Handlers can be tricky with typescript and React. But because you have a basic understanding of how Generics work- it should make sense. We have a generic type that we can pass in more specific types to. In this case, we're clicking a button, so we use the . If we wanted to accurately get the event from other elements on a mouse click, we could pass in their respective type.

<div> -> HTMLDivElement
<a> -> HTMLAnchorElement
<body> -> HTMLBodyElement
... etc ...

If we want to make this handler work for multiple types of elements, there's always which should mean .

Ahh that's still confusing

It might seem complicated at first- but you just need to break it up into 2 parts:

  • What kind of event is it?
  • What element is it being triggered on? So if we wanted the type for the event triggered in an <input> tag we'd use: React.ChangeEvent<HTMLInputElement> If we wanted the onChange for a <select> tag, we'd use: React.ChangeEvent<HTMLSelectElement> If we wanted the for an <input> tag, we'd use: React.KeyboardEvent<HTMLInputElement>

You'll get used to the event handler names pretty quick- and you'll stop using and cheating ;)

Loading...

0 Comments

user image
John Doe   23 Feb 2025

How do I remove the blur effect from my CSS?

user image
Alice Johnson   23 Feb 2025

I removed but the blur is still there. Any ideas?

filter: blur(5px);
user image
Charlie Brown   23 Feb 2025

Does work for removing blur from modals?

backdrop-filter: none;
glass-bbok

Join the Conversation!

Subscribing gives you access to the comments so you can share your ideas, ask questions, and connect with others.

Upgrade your account
tick-guideNext Lesson

Progress