首页 > 解决方案 > 如何在 Redux 中创建另一个包含两个 reducer 的状态来更新状态

问题描述

我正在使用 React/Redux 创建一个电影应用程序,它允许用户通过单击一个按钮(买票)来选择一部电影,该按钮将用户带到另一个页面以选择票的数量并将他的购买添加到购物车.

这个想法是当用户点击按钮添加到卡片时,我希望发生两件事,一是应该在导航栏中的徽章购物车中更新数量,如果用户想要结帐,还应该将此电影添加到包中.

当我单击添加到购物车时,如何在减速器中创建一个名为购物车的状态来更新数量并将电影添加到该购物车中?

你怎么看?

<-- 动作类型-->

export const ActionsTypes = {
     SET_MOVIES : "SET_MOVIES",
     GET_MOVIE : "GET_MOVIE", 
     REMOVE_MOVIE : "REMOVE_MOVIE",
     QUANTITY: "QUANTITY",
 }

<-- 数量动作-->

export const MovieQuantity = () => {
    return {
        type : ActionsTypes.QUANTITY
    }
}

<-- 减速器-->

const initialState = {
    movies: [],
};

//Movies Reducers
export const setMoviesReducers = (state = initialState, action) => {
    switch (action.type) {
        case ActionsTypes.SET_MOVIES:
            return {...state, movies: action.payload }
        default:
            return state;
    }
}

// single Movies Reducers
export const GetMovieDetailsReducers = (state={}, action) => {
    switch(action.type) {
        case ActionsTypes.GET_MOVIE : 
            return {...state, ...action.payload}
        case ActionsTypes.REMOVE_MOVIE : 
            return {};
        default : 
            return state
    }
    
}

export const movieQuantityReducers = (state = 0 , action) => {
        switch(action.type) {
            case ActionsTypes.QUANTITY: 
               return state + 1;
            default :  
               return state;
        }
}

<-- 电影详情添加到购物车组件-->

const MovieDetails = () => {
    const [quantity, setQuantity] = useState(1) 
    const singleMovie = useSelector((state)=> state.movie);
    const quantityBag = useSelector((state)=> state.quantity);
    const {title, poster_path, overview} = singleMovie;
    const dispatch = useDispatch();
    let {movieId} = useParams();

    
    // Handle Click Quantity
    const handleQuantity = (type) => {
        if(type === "dec") {
            quantity > 1 && setQuantity(quantity - 1)
        } else {
            setQuantity(quantity + 1)
        }
    }

    // add to cart Handler
    const CartHandler = () => {
        dispatch(MovieQuantity(quantityBag)) // the quantity is just incrementing
    }


    // Get a single Product & Remove product
    useEffect(()=> {
        try {
            const getSingleMovie = async () => {
                const request = await axios.get(`https://api.themoviedb.org/3/movie/${movieId}?api_key=&&&&&`);
                const response = await request.data;
                dispatch(getMovie(response))
            }

            getSingleMovie();

        } catch(error) {
            console.log(`ERROR : ${error}`)
        }

        //Clean up
        return () => {
            dispatch(removeMovie());
        }
            
    }, [movieId])


    return (
        <section className="movieDetails_container">
            <div className="wrapper">
                <div className="img-container">
                    <img src={`${ImgPath}` + poster_path} alt={title}/>
                </div>

                <div className="info-container">
                    <h1>{title}</h1>
                    <p>{overview}</p>
                    <div className="quantity-container">
                        <Remove className="quantity-icon" onClick={()=> handleQuantity("dec")}/>
                        <span className="amount">{quantity}</span>
                        <Add className="quantity-icon" onClick={()=> handleQuantity("incr")}/>
                    </div>
                    <button className="btn-add" onClick={()=> CartHandler()}>Add To Cart</button>
                </div>
                
            </div> 
        </section>
    )
}

export default MovieDetails

<-- 导航栏组件 -->

const Navbar = () => {
    const quantityBag = useSelector((state)=> state.quantity);
    return (
        <nav className="navBar-section">
            <Link to="/">
                <h1 className="logo">映画館&lt;/h1>
            </Link>

            <Badge badgeContent={quantityBag} color="primary">
                 <LocalMall className="icon-bag" />
            </Badge>
        </nav>
    )
}

export default Navbar

标签: reactjsredux

解决方案


我会以不同的方式对状态进行建模。根据您的描述,以下内容会很好地工作:

const state = {
    // movie details reducer handles this part:
    movies: {
        "movie1Id": {
            "name": "Title of movie1"
            // more movie details here
        },
        "movie2Id": {
            "name": "Title of movie2"
            // more movie details here
        },
    },

    // cart reducer handles this part:
    cart: {
        "movie1Id": 3, // quantity. user chose 3 tickets for movie1.
        "movie2Id": 1, // quantity. user chose 1 ticket for movie2.
    }
};

const setCartItemAction = (movieId, quantity) => ({
    type: "SET_CART_ITEM",
    payload: { movieId, quantity }
});

setCartItemAction足以为您的用例建模。为某部电影调用它的数量与0从购物车中删除该电影相同。


推荐阅读