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)