redux reflect all reducer changes in UI

Viewed 21

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
        }
    }
0 Answers
Related