Reputation: 121
I have a data which I receive from Redux Store, also I have categories by which I need to filter data by clicking on appropriate category button. How can I implement filter using Redux? items from database has output like this:
items = [{
id: 0
name: "example1"
price: 15
category: 0
},
{
id: 1
name: "example2"
price: 15
category: 1
}
]
categories has output:
categories = ["one", "two"]
This is my Component:
export default function Home() {
const itemData = useSelector((state) => state.main.items);
const loader = useSelector((state) => state.load.loading);
const [activeCategory, setActiveCategory] = useState(null);
const dispatch = useDispatch();
useEffect(() => {
dispatch(fetchItems());
}, [dispatch]);
if (loader) {
return <Spinner />;
}
return (
<div className="container">
<div className="content__top">
<div className="categories">
<ul>
<li
className={activeCategory === null ? 'active' : ''}
onClick={() => setActiveCategory(null)}>
All
</li>
{categories &&
categories.map((category, index) => (
<li
key={index}
className={activeCategory === index ? 'active' : ''}
onMouseDown={() => dispatch(filterByCategory(itemData, category))}
onClick={() => setActiveCategory(index)}>
{category}
</li>
))}
</ul>
</div>
</div>
<h2 className="content__title">Items</h2>
<div className="content__items">
{itemData && itemData.map((item) => <Content key={item._id} {...item} />)}
</div>
</div>
);
}
This is my Action:
export const FETCH_ITEMS = 'FETCH_ITEMS';
export const FILTER_BY_CATEGORY = 'FILTER_BY_CATEGORY';
export const fetchItems = () => {
return (dispatch) => {
dispatch(showLoader());
axios.get('http://localhost:4000/').then((response) => {
const items = response.data;
dispatch({
type: FETCH_ITEMS,
payload: items,
});
dispatch(hideLoader());
});
};
};
export const filterByCategory = (items, category) => {
return {
type: FILTER_BY_CATEGORY,
category,
// some kind of filter code
};
};
And Reducer
const initialState = {
items: [],
};
export const fetchReducer = (state = initialState, action) => {
switch (action.type) {
case actions.FETCH_ITEMS:
return { ...state, items: action.payload };
case actions.FILTER_BY_CATEGORY:
return { ...state, filtered: action.category, category }; // Not sure about it
default:
return state;
}
};
Upvotes: 2
Views: 750
Reputation: 39250
Here is a working example using selectors:
const { Provider, useSelector } = ReactRedux;
const { createStore, applyMiddleware, compose } = Redux;
const { createSelector } = Reselect;
const initialState = {
items: [
{
id: 0,
name: 'example1',
price: 15,
category: 0,
},
{
id: 1,
name: 'example2',
price: 15,
category: 1,
},
{
id: 2,
name: 'example3',
price: 88,
category: 1,
},
],
};
const reducer = (state) => state;
//selectors
const selectItems = (state) => state.items;
const selectCategories = createSelector(
[selectItems],
(items) => [
...new Set(
items.map(({ category }) => category).sort()
),
]
);
const createSelectFilteredItems = (filterFunction) =>
createSelector([selectItems], (items) =>
items.filter(filterFunction)
);
//creating store with redux dev tools
const composeEnhancers =
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
reducer,
initialState,
composeEnhancers(
applyMiddleware(() => (next) => (action) =>
next(action)
)
)
);
const App = () => {
const categories = useSelector(selectCategories);
const [
selectedCategory,
setSelectedCategory,
] = React.useState();
const selectFilteredItems = React.useMemo(
() =>
createSelectFilteredItems(({ category }) =>
selectedCategory === undefined
? true
: category === selectedCategory
),
[selectedCategory]
);
const filteredItems = useSelector(selectFilteredItems);
return (
<div>
<label>
select category
<select
value={selectedCategory}
onChange={({ target: { value } }) =>
setSelectedCategory(
value === 'all' ? undefined : Number(value)
)
}
>
<option value="all">all</option>
{categories.map((category) => (
<option key={category} value={category}>
{category}
</option>
))}
</select>
</label>
<ul>
{filteredItems.map((item) => (
<li key={item.id}>{JSON.stringify(item)}</li>
))}
</ul>
</div>
);
};
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.2.0/react-redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/reselect/4.0.0/reselect.min.js"></script>
<div id="root"></div>
Upvotes: 3