Skip to content

Commit

Permalink
refactor: optimize selectors
Browse files Browse the repository at this point in the history
  • Loading branch information
Valik3201 committed Feb 20, 2024
1 parent b36ce41 commit 84a7e7a
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 41 deletions.
75 changes: 37 additions & 38 deletions src/components/ContactList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { deleteContact, fetchContacts } from '../redux/operations/operations';
import {
selectContacts,
selectFilter,
selectVisibleContacts,
selectIsLoading,
selectError,
} from '../redux/selectors/contactsSelectors';

import {
Expand All @@ -23,25 +24,22 @@ import { Trash2 } from 'lucide-react';
* @returns {JSX.Element} The JSX element representing the contact list.
*/
const ContactList = () => {
const filter = useSelector(selectFilter);
const dispatch = useDispatch();

const { items, isLoading, error } = useSelector(selectContacts);
const items = useSelector(selectVisibleContacts);
const isLoading = useSelector(selectIsLoading);
const error = useSelector(selectError);

useEffect(() => {
dispatch(fetchContacts());
}, [dispatch]);

const filteredContacts = items.filter(i =>
i.name.toLowerCase().includes(filter?.toLowerCase())
);

/**
* Sorts contacts alphabetically by name.
* @type {Array}
*/
const sortedContacts = filteredContacts
?.slice()
const sortedContacts = items
.slice()
.sort((a, b) => a.name.localeCompare(b.name));

/**
Expand All @@ -63,7 +61,7 @@ const ContactList = () => {
<TableColumn className="w-1/5 text-center">ACTIONS</TableColumn>
</TableHeader>
<TableBody emptyContent={'No contacts to display.'}>
{isLoading && (
{isLoading && !error && (
<TableRow>
<TableCell aria-colspan={3} colSpan={3} className="text-center">
<Spinner />
Expand All @@ -87,34 +85,35 @@ const ContactList = () => {
</TableRow>
)}

{sortedContacts.map(contact => (
<TableRow key={contact.id}>
<TableCell>{contact.name}</TableCell>
<TableCell>{contact.phone}</TableCell>
<TableCell className="text-center">
<Button
color="danger"
variant="light"
size="sm"
startContent={<Trash2 className="w-4 h-4" />}
onClick={() => handleDelete(contact.id)}
className="hidden md:flex"
>
Delete
</Button>
{!isLoading &&
sortedContacts.map(contact => (
<TableRow key={contact.id}>
<TableCell>{contact.name}</TableCell>
<TableCell>{contact.phone}</TableCell>
<TableCell className="text-center">
<Button
color="danger"
variant="light"
size="sm"
startContent={<Trash2 className="w-4 h-4" />}
onClick={() => handleDelete(contact.id)}
className="hidden md:flex"
>
Delete
</Button>

<Button
color="danger"
variant="light"
isIconOnly
onClick={() => handleDelete(contact.id)}
className="md:hidden"
>
<Trash2 className="w-4 h-4" />
</Button>
</TableCell>
</TableRow>
))}
<Button
color="danger"
variant="light"
isIconOnly
onClick={() => handleDelete(contact.id)}
className="md:hidden"
>
<Trash2 className="w-4 h-4" />
</Button>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
);
Expand Down
17 changes: 14 additions & 3 deletions src/redux/selectors/contactsSelectors.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
export const selectContacts = state => state.contacts;
import { createSelector } from '@reduxjs/toolkit';

export const selectIsLoading = state => state.tasks.isLoading;
export const selectContacts = state => state.contacts.items;

export const seelctError = state => state.tasks.error;
export const selectIsLoading = state => state.contacts.isLoading;

export const selectError = state => state.contacts.error;

export const selectFilter = state => state.filter;

export const selectVisibleContacts = createSelector(
[selectContacts, selectFilter],
(contacts, filter) => {
return contacts.filter(contact =>
contact.name.toLowerCase().includes(filter.toLowerCase())
);
}
);

0 comments on commit 84a7e7a

Please sign in to comment.