Let's say that somewhere in our application we fetch a list of users and the following interface describes the user object.
interface User {
address: string;
createdAt: string;
email: string;
firstName: string;
id: number;
lastName: string;
phone: string;
updatedAt: string;
}
Then we have a function component that renders each user's first and last name next to a checkbox.
import React from 'react';
import { useSelector } from 'react-redux';
import { usersSelector } from './selectors';
function UserList(): JSX.Element {
const users = useSelector(usersSelector);
return (
<ul>
{users.map(({ firstName, id, lastName }, index) => (
<li key={index}>
<input type="checkbox" value={id} />
{firstName} {lastName}
</li>
))}
</ul>
)
}
Each time a checkbox is clicked we need to send a request to an endpoint with the following payload.
interface Payload {
selectedUsers: number[];
}
The only thing that changes is the payload, so let's keep it in a state.
import React, { useState } from 'react';
import { useSelector } from 'react-redux';
import { usersSelector } from './selectors';
function UserList(): JSX.Element {
const users = useSelector(usersSelector);
const [selectedUsers, setSelectedUsers] = useState<number[]>([]);
return (
<ul>
{users.map(({ firstName, id, lastName }, index) => (
<li key={index}>
<input
checked={selectedUsers.includes(id)}
type="checkbox"
value={id}
/>
{firstName} {lastName}
</li>
))}
</ul>
)
}
Now let's add a handler to update our payload on each checkbox click.
import xor from 'lodash/xor';
import React, { useState } from 'react';
import { useSelector } from 'react-redux';
import { usersSelector } from './selectors';
function UserList(): JSX.Element {
const users = useSelector(usersSelector);
const [selectedUsers, setSelectedUsers] = useState<number[]>([]);
const handleChange =
(event: React.ChangeEvent<HTMLInputElement>): void => {
const target = event.target;
const value = target.value;
setSelectedUsers(prev => xor(prev, [value]));
}
return (
<ul>
{users.map(({ firstName, id, lastName }, index) => (
<li key={index}>
<input
checked={selectedUsers.includes(id)}
onChange={handleChange}
type="checkbox"
value={id}
/>
{firstName} {lastName}
</li>
))}
</ul>
)
}
Let's run an effect on every UI update to make that request.
import xor from 'lodash/xor';
import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { selectUsers } from './actions';
import { usersSelector } from './selectors';
function UserList(): JSX.Element {
const dispatch = useDispatch();
const users = useSelector(usersSelector);
const [selectedUsers, setSelectedUsers] = useState<number[]>([]);
useEffect(() => {
dispatch(selectUsers(selectedUsers));
}, [dispatch, selectedUsers]);
const handleChange =
(event: React.ChangeEvent<HTMLInputElement>): void => {
const target = event.target;
const value = target.value;
setSelectedUsers(prev => xor(prev, [value]));
}
return (
<ul>
{users.map(({ firstName, id, lastName }, index) => (
<li key={index}>
<input
checked={selectedUsers.includes(id)}
onChange={handleChange}
type="checkbox"
value={id}
/>
{firstName} {lastName}
</li>
))}
</ul>
)
}
Usually, we'd get a response back with the selectedUsers
so as last step we would like to indicate the selected users in our UI as well.
//
function UserList(): JSX.Element {
const users = useSelector(usersSelector);
const selectedUsersFromState = useSelector(
selectedUsersFromStateSelector
);
const [selectedUsers, setSelectedUsers] = useState<number[]>(
selectedUsersFromState
);
//
Top comments (0)