This is the filterAction
action that emits a value to to the persisted reducer. This action is called with dispatch()
in a dropdown in a component.
import { SORT_BY_TITLE, SORT_BY_RELEASED_AT } from './types';
// sort by title
export const sortByTitle = () => ({
type: SORT_BY_TITLE
});
// sort by released at
export const sortByReleasedAt = () => ({
type: SORT_BY_RELEASED_AT
});
The corresponding filterReducer
import { SORT_BY_TITLE, SORT_BY_RELEASED_AT } from '../actions/types';
const initialState = {
sortBy: 'title'
};
export default function(state = initialState, action) {
switch(action.type) {
case SORT_BY_TITLE:
return {
...state,
sortBy: 'title'
};
case SORT_BY_RELEASED_AT:
return {
...state,
sortBy: 'releasedAt'
};
default:
return state;
}
};
The filterReducer
value is the one persisted in the main combined reducer.
export default combineReducers({
books: booksReducer,
book: bookReducer,
form: addBookFormReducer,
filter: filterReducer
});
The app's store
import { createStore, applyMiddleware } from 'redux';
import { persistStore, persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage';
import thunk from 'redux-thunk';
import rootReducer from './reducers/index';
const middleware = [thunk];
const persistConfig = {
key: 'root',
storage,
whitelist: ['filter']
};
const persistedReducer = persistReducer(persistConfig, rootReducer);
export const store = createStore(persistedReducer, {}, applyMiddleware(...middleware));
export const persistor = persistStore(store);
The value persisted on the filter
part of the main reducer gets displayed in the dropdown changes on which call the filterAction
with dispatch()
.
Here's the booksReducer
that creates the books
part of the app's store
so books
are displayed in a component.
import {
GET_BOOKS,
BOOKS_LOADING,
DELETE_BOOK,
SORT_BY_TITLE,
SORT_BY_RELEASED_AT
} from '../actions/types';
const initialState = {
books: [],
loading: false
};
const booksReducer = (state = initialState, action) => {
switch(action.type) {
case BOOKS_LOADING:
return {
...state,
loading: true
};
case GET_BOOKS:
return {
...state,
books: action.payload,
loading: false
};
case DELETE_BOOK:
return {
books: [...state.books.filter(book => book._id !== action.payload.id)]
};
case SORT_BY_TITLE:
return {
...state,
books: [...state.books.sort((a, b) => a.title < b.title ? -1 : 1 )]
};
case SORT_BY_RELEASED_AT:
return {
...state,
books: [...state.books.sort((a, b) => a.releasedAt < b.releasedAt ? -1 : 1 )]
};
default:
return state;
}
};
export default booksReducer;
The filter
part of the main reducer persists Ok on the page reload however the books
list is displayed with the default by title sort.
How do I get the app to persist the sort on the page reload? The complete repo is on https://github.com/ElAnonimo/booklister
On the BookList
load the getBooks()
action return reset the sorted books list to its default sorting so it was easier to persist only the filter
prop of the store
then sort the books
list on each load of the BookList
component.
The changes were made
to booksReducer
import {
GET_BOOKS,
BOOKS_LOADING,
DELETE_BOOK
} from '../actions/types';
const initialState = {
books: [],
loading: false
};
const booksReducer = (state = initialState, action) => {
switch(action.type) {
case BOOKS_LOADING:
return {
...state,
loading: true
};
case GET_BOOKS:
return {
...state,
books: action.payload,
loading: false
};
case DELETE_BOOK:
return {
books: [...state.books.filter(book => book._id !== action.payload.id)]
};
default:
return state;
}
};
export default booksReducer;
to BookList
class BookList extends Component {
componentDidMount() {
this.props.getBooks();
}
applySorting(books) {
const sortBy = this.props.filter.sortBy;
if (!sortBy) {
return books;
}
return books.sort((a, b) => a[sortBy] < b[sortBy] ? -1 : 1);
}
render() {
const { books, loading } = this.props.books;
let booksContent;
if (!books || loading) {
booksContent = <Spinner />;
} else {
if (books.length > 0) {
booksContent = this.applySorting(books).map(book => <BookItem book={book} key={book._id} />);
} else {
booksContent = <h4>No books found</h4>;
}
}
...
...