DEV Community

Ioannis Potouridis
Ioannis Potouridis

Posted on • Edited on

How I usually write my React components.

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)