We have created a React Application that connects with Redux. In this tutorial, we’re gonna filter list of items with input text using react-redux.
Contents
Example Overview
We will build a React Application that has input text to look up for filtering items.
The filter works and updates every time we type in the textbox.
Filter list with input text
Context
Remember that our App state is like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
const demoState = { books: [ { id: '123abcdefghiklmn', title: 'Origin', description: 'Origin thrusts Robert Langdon into the dangerous intersection of humankind’s two most enduring questions.', author: 'Dan Brown', published: 2017 } ], filters: { text: 'ori', sortBy: 'published', // published or title startYear: undefined, endYear: undefined } }; |
And our Book list is displayed based on getVisibleBooks()
function:
1 2 3 4 5 6 7 8 9 10 11 12 |
// BookList.js const BookList = (props) => ( // display 'books' ); const mapStateToProps = (state) => { return { books: getVisibleBooks(state.books, state.filters) }; } export default connect(mapStateToProps)(BookList); |
getVisibleBooks(books, filters)
returns Book list by filtering and sorting input books.
1 2 3 4 5 6 7 8 9 |
// getVisibleBooks export default (books, { text, sortBy, startYear, endYear }) => { return books.filter(book => { // ... return textMatch && startYearMatch && endYearMatch; }).sort((book1, book2) => { // sort by title/published }); } |
=> Updating filters
state will change the list of displayed item (books
).
Solution
In this example, we only update filters.text
. To do this, we need:
– input text box to receive characters => create BookFilters Component that has html input
.
– to connect BookFilters Component with Redux store to get access to filters
state => import react-redux connect()
and use mapStateToProps
.
– to update result every time characters are typed => add onChange
event and use Redux dispatch()
with filterText
Action imported from actions/filters.
Practice
Create BookFilters Component
Inside components folder, create BookFilters.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import React from 'react'; import { connect } from 'react-redux'; import { filterText } from '../actions/filters'; const BookFilters = (props) => ( <div style={{ marginBottom: 15 }}> <input type='text' placeholder='search' value={props.filters.text} onChange={(e) => { props.dispatch(filterText(e.target.value)); }}></input> </div> ); const mapStateToProps = (state) => { return { filters: state.filters } } export default connect(mapStateToProps)(BookFilters); |
Add BookFilters to its parent Component
DashBoard.js:
1 2 3 4 5 6 7 8 9 10 11 12 |
import React from 'react'; import BookList from './BookList'; import BookFilter from './BookFilter'; const DashBoard = () => ( <div className='container__list'> <BookFilter /> <BookList /> </div> ); export default DashBoard; |
Run and Check Result
app.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
import React from 'react'; import ReactDOM from 'react-dom'; import AppRouter from './routers/AppRouter'; import getAppStore from './store/store'; import { addBook } from './actions/books'; import { filterText, startYear, endYear, sortBy, clear } from './actions/filters'; import getVisibleBooks from './selectors/books'; import './styles/styles.scss'; import { Provider } from 'react-redux'; const store = getAppStore(); store.dispatch(addBook({ title: 'Origin', description: 'Origin thrusts Robert Langdon into the dangerous intersection of humankind’s two most enduring questions.', author: 'Dan Brown', published: 2017 })); store.dispatch(addBook({ title: 'Harry Potter and the Goblet of Fire', description: 'A young wizard finds himself competing in a hazardous tournament between rival schools of magic, but he is distracted by recurring nightmares.', author: 'J. K. Rowling', published: 2000 })); store.dispatch(addBook({ title: 'Harry Potter and the Deathly Hallows', description: 'The seventh and final novel of the Harry Potter series.', author: 'J. K. Rowling', published: 2007 })); store.dispatch(addBook({ title: 'The 100-Year-Old Man Who Climbed Out the Window and Disappeared', author: 'Jonas Jonasson', published: 2009 })); const template = ( <Provider store={store}> <AppRouter /> </Provider> ); ReactDOM.render(template, document.getElementById('app')); |
Check Result
Source Code
For running:
– yarn install
– yarn run dev-server
or yarn run build
, then yarn run serve
.
More Practice
Year Filters
BookFilters.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
import React from 'react'; import { connect } from 'react-redux'; import { filterText, startYear, endYear } from '../actions/filters'; class BookFilters extends React.Component { constructor(props) { super(props); this.filterYear = this.filterYear.bind(this); } filterYear() { let start = (+this.startYear.value) !== 0 ? (+this.startYear.value) : undefined; let end = (+this.endYear.value) !== 0 ? (+this.endYear.value) : undefined; this.props.dispatch(startYear(start)); this.props.dispatch(endYear(end)); } render() { return ( <div style={{ marginBottom: 15 }}> <input type='text' placeholder='search' value={this.props.filters.text} onChange={(e) => { this.props.dispatch(filterText(e.target.value)); }}></input> <br /><br /> <input type='number' placeholder='startYear' style={{ width: 80 }} ref={el => this.startYear = el}></input> <input type='number' placeholder='endYear' style={{ width: 80 }} ref={el => this.endYear = el}></input> <button onClick={this.filterYear}>-></button> </div> ); } } const mapStateToProps = (state) => { return { filters: state.filters } } export default connect(mapStateToProps)(BookFilters); |
Result: