I'm trying to display a list of burgers, where a user can filter and sort the list and even give stars to his favorite burger. All of my actions work as expected, but I am not sure how to setup my UI, so it reflects all the changes I make. Right now I render my list from the state of only one reducer at a time (using 'burgers', 'filter' OR 'sort' to map over my data). What can I do to combine that?
app.js
import Card from './Components/Card.js';
import './App.css';
import { useSelector, useDispatch } from 'react-redux';
import * as actions from './Components/actions.js';
function App() {
const burgers = useSelector(state => state.starCount);
const filter = useSelector(state => state.filterBurgers);
const sort = useSelector(state => state.burgers);
const dispatch = useDispatch();
const handleChange = (e) => {
const value = e.target.value;
dispatch(actions.filterBurgers(value));
}
const changeSort = (e) => {
const value = e.target.value;
dispatch(actions.sortBurgers(value));
}
return (
<div className="App">
<div className="App-header">
<label>Sort by</label>
<select name="sort" id="sort" value="" onChange={changeSort}>
<option value="" disabled hidden>Choose an option</option>
<option value="name">Name</option>
<option value="price">Price</option>
</select>
<label>Filter by</label>
<select name="filter" id="filter" onChange={handleChange}>
<option value="" disabled selected hidden>Choose an option</option>
<option value="cheese">Cheese</option>
<option value="doubleMeat">Double Meat</option>
</select>
</div>
<div style={{display: 'flex', flexDirection: 'column'}}>
{sort.map((item) =>
<Card img={item.image} title={item.name} price={item.price} stars={item.stars} key={item.name} id={item.id}/>
)}
</div>
</div>
);
}
export default App;
Card.js (triggers the starcount action)
import './card.css'
import { BsFillStarFill } from "react-icons/bs";
import { useSelector, useDispatch } from 'react-redux';
import * as actions from './actions';
export default function Card(props) {
const { title, price, stars, img, id } = props;
//const burgers = useSelector(state => state.starCount);
const dispatch = useDispatch();
const handleClick = event => {
dispatch(actions.addStar(event.currentTarget.id));
};
return (<div className="card">
<div className="card-header">
</div>
<div className="card-body">
<div className="card-title">{title}</div>
<div className="price">Price: ${price}</div>
<div className="rating" id={id} onClick={handleClick}>
<div className="star">
<BsFillStarFill />
</div>
<div className="count">
{stars}
</div>
</div>
</div>
</div>)
}
reducers/index.js
import { combineReducers } from 'redux';
import { sortBurgers, updateStarCount, filterBurgers } from './sortBurgers.js';
const rootReducer = combineReducers({
starCount: updateStarCount,
burgers: sortBurgers,
filterBurgers: filterBurgers
})
export default rootReducer;
reducers/sortBurgers.js
export const burgers = [
{
id: 1,
image: hamburger,
name: "Hamburger",
price: 1.25,
stars: 0,
cheese: false,
doubleMeat: false
},
{
id: 2,
image: baconBurger,
name: "Bacon Burger",
price: 2.50,
stars: 0,
cheese: false,
doubleMeat: false
},
{
id: 3,
image: doubleMeatBurger,
name: "Double Meat Burger",
price: 3.75,
stars: 0,
cheese: true,
doubleMeat: true
},
{
id: 4,
image: doubleCheeseBurger,
name: "Double Cheese Burger",
price: 5.00,
stars: 0,
cheese: true,
doubleMeat: true
}
]
export const sortBurgers = (state = burgers, action) => {
switch(action.type) {
case 'SORT_BURGERS':
switch(action.payload.value) {
case "name":
return state.slice().sort(function(a, b) {
let nameA = a.name,
nameB = b.name
if (nameA < nameB)
return -1
if (nameA > nameB)
return 1
return 0
});
case "price":
return state.slice().sort(function(a, b) {
let nameA = a.price,
nameB = b.price
if (nameA < nameB)
return -1
if (nameA > nameB)
return 1
return 0
});
default: return state;
}
default:
return state;
}
}
export const filterBurgers = (state = burgers, action) => {
switch(action.type) {
case actions.FILTER_BURGERS:
if(action.payload.value === 'cheese')
{
return state.filter(burger => burger.cheese === true);
}
else if(action.payload.value === 'doubleMeat') {
return state.filter(burger => burger.doubleMeat === true);
} else {
return state;
}
default:
return state;
}
}
export const updateStarCount = (state = burgers, action) => {
switch(action.type) {
case 'ADD_STAR':
return state.map((burger) => {
if (burger.id === action.payload.id) burger.stars++;
return burger;
})
default:
return state
}
}