Overview
The filter slice manages the podcast list filtering and pagination state. It’s a simple slice that controls:
Which category filter is active (all, favorites, completed, etc.)
Current page number
Items per page setting
State Shape
{
currentFilter : "todos" , // Active filter: "todos" | "favoritos" | "empezados" | "completados" | "escuchar-mas-tarde"
currentPage : 1 , // Current page number (1-indexed)
songsPerPage : 12 // Number of episodes per page
}
State Properties
The active filter category. Possible values:
"todos" - All episodes
"favoritos" - Favorite episodes
"empezados" - Started episodes
"completados" - Completed episodes
"escuchar-mas-tarde" - Listen later episodes
The current page number in the paginated episode list. Pages start at 1.
Number of episodes to display per page. This is currently a constant value.
Actions
setFilter
Sets the active filter and resets pagination to page 1.
The filter to activate. Must be one of:
"todos"
"favoritos"
"empezados"
"completados"
"escuchar-mas-tarde"
dispatch ( setFilter ( "favoritos" ));
Reducer Logic:
src/store/slices/filterSlice.js
setFilter : ( state , action ) => {
state . currentFilter = action . payload ;
state . currentPage = 1 ; // Reset to first page
}
Setting a new filter automatically resets the page to 1, ensuring users start at the beginning of the filtered list.
Usage Example:
const handleSearchChange = ( e ) => {
// Reset filter to "todos" when searching
dispatch ( setFilter ( "todos" ));
dispatch ( setSearchTerm ( e . target . value ));
};
setCurrentPage
Changes the current page number.
The page number to navigate to (1-indexed)
dispatch ( setCurrentPage ( 3 ));
Reducer Logic:
src/store/slices/filterSlice.js
setCurrentPage : ( state , action ) => {
state . currentPage = action . payload ;
}
Selectors
Access filter state in components:
import { useSelector } from 'react-redux' ;
const MyComponent = () => {
const { currentFilter , currentPage , songsPerPage } = useSelector (
( state ) => state . filter
);
// Use the state...
};
Filter Options
The available filter categories map to user collections:
todos Shows all podcast episodes
favoritos Shows episodes in favoriteEpisodes array
empezados Shows episodes with saved playback times
completados Shows episodes in completedEpisodes array
escuchar-mas-tarde Shows episodes in listenLaterEpisodes array
Components use the filter state to calculate which episodes to display:
const { currentPage , songsPerPage } = useSelector (
( state ) => state . filter
);
// Calculate pagination indices
const indexOfLastSong = currentPage * songsPerPage ;
const indexOfFirstSong = indexOfLastSong - songsPerPage ;
// Get current page of episodes
const currentSongs = filteredEpisodes . slice (
indexOfFirstSong ,
indexOfLastSong
);
// Calculate total pages
const totalPages = Math . ceil ( filteredEpisodes . length / songsPerPage );
Filter Integration Example
Typical usage pattern in a podcast list component:
import { useSelector , useDispatch } from 'react-redux' ;
import { setFilter , setCurrentPage } from './store/slices/filterSlice' ;
const PodcastList = () => {
const dispatch = useDispatch ();
// Get all relevant state
const { songs , favoriteEpisodes , completedEpisodes , searchTerm } =
useSelector (( state ) => state . podcast );
const { playbackTimes } = useSelector (( state ) => state . audioTime );
const { currentFilter , currentPage , songsPerPage } =
useSelector (( state ) => state . filter );
// Filter episodes based on currentFilter
const getFilteredSongs = () => {
let filtered = songs ;
switch ( currentFilter ) {
case "favoritos" :
filtered = songs . filter ( song =>
favoriteEpisodes . includes ( song . title )
);
break ;
case "empezados" :
filtered = songs . filter ( song =>
playbackTimes [ song . title ] > 0
);
break ;
case "completados" :
filtered = songs . filter ( song =>
completedEpisodes . includes ( song . title )
);
break ;
// ... other cases
}
// Apply search filter
if ( searchTerm ) {
filtered = filtered . filter ( song =>
song . title . toLowerCase (). includes ( searchTerm . toLowerCase ())
);
}
return filtered ;
};
const filteredSongs = getFilteredSongs ();
// Pagination
const indexOfLastSong = currentPage * songsPerPage ;
const indexOfFirstSong = indexOfLastSong - songsPerPage ;
const currentSongs = filteredSongs . slice (
indexOfFirstSong ,
indexOfLastSong
);
return (
< div >
{ /* Filter buttons */ }
< button onClick = { () => dispatch ( setFilter ( "todos" )) }
Todos
</button>
<button onClick = { () => dispatch ( setFilter ( "favoritos" )) }
Favoritos
</button>
{ /* Episode list */ }
{ currentSongs . map ( song => (
< Episode key = { song . title } episode = { song } />
)) }
{ /* Pagination */ }
<Pagination
currentPage = { currentPage }
totalPages = { Math . ceil ( filteredSongs . length / songsPerPage ) }
onPageChange = { ( page ) => dispatch ( setCurrentPage ( page )) }
/>
</ div >
);
};
Filter State Interactions
User Selects Filter
dispatch ( setFilter ( "favoritos" ));
Filter changes and page resets to 1
Episodes Are Filtered
Component filters the songs array based on currentFilter
Pagination Applied
Filtered episodes are sliced based on currentPage and songsPerPage
User Changes Page
dispatch ( setCurrentPage ( 2 ));
New page of episodes is displayed
Search Integration
When a user searches, the filter automatically resets to “todos”:
const handleSearchChange = ( e ) => {
dispatch ( setFilter ( "todos" ));
dispatch ( setSearchTerm ( e . target . value ));
};
This ensures search results include all episodes, not just the currently filtered ones.
Complete Action Reference
import {
setFilter , // Set active filter
setCurrentPage // Change page number
} from './store/slices/filterSlice' ;
State Persistence
The filter slice does not persist to localStorage. Filter and pagination state reset when the page is refreshed.
If you want to persist the filter state:
// Save to localStorage
localStorage . setItem ( 'nsnCurrentFilter' , currentFilter );
localStorage . setItem ( 'nsnCurrentPage' , currentPage );
// Load in initialState
initialState : {
currentFilter : localStorage . getItem ( 'nsnCurrentFilter' ) || 'todos' ,
currentPage : parseInt ( localStorage . getItem ( 'nsnCurrentPage' )) || 1 ,
songsPerPage : 12
}
Customizing Items Per Page
The songsPerPage value is currently fixed at 12. To make it dynamic:
// Add a new action
setSongsPerPage : ( state , action ) => {
state . songsPerPage = action . payload ;
state . currentPage = 1 ; // Reset page when changing items per page
}
// Usage
dispatch ( setSongsPerPage ( 24 ));
Filter Categories Reference
All episodes - no filtering applied
Episodes in the favoriteEpisodes array from podcast slice
Episodes with playbackTimes[title] > 0 from audio time slice
Episodes in the completedEpisodes array from podcast slice
Episodes in the listenLaterEpisodes array from podcast slice