react路由跳转和store存储

下载router:npm i react-router-dom

下载redux:npm i @reduxjs/toolkit

下载store:npm i store

下载react-redux:npm i react redux

1.创建组件

2.创建router文件夹,里面创建index.js

import { createBrowserRouter,Navigate } from "react-router-dom";

//导入组件

import List from '../components/List'

import Cart from '../components/Cart'

//路由表

const router = createBrowserRouter([

    {

        path:'/list',

        element:<List/>

    },

    {

        path:'/cart',

        element:<Cart/>

    },

    {

        path:'/',

        element:<Navigate to='/list'/>

    },

])

export default router

3. 在index.js组件内导入router进行使用

import React from 'react';

import ReactDOM from 'react-dom/client';

import { RouterProvider } from 'react-router-dom'

import router from './router';

const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(

  <React.StrictMode>

      <RouterProvider router={router}/>

  </React.StrictMode>

);

4.创建store文件夹,创建一个modules,创建一个cart.js文件

import { createSlice } from '@reduxjs/toolkit'

// 封装一个数据持久化的方法

const storage = {

    setStorage(key,value){

        sessionStorage[key] = JSON.stringify(value)

    },

    getStorage(key){

        return JSON.parse(sessionStorage[key] || '[]')

    }

}

// 进行切分

const cart = createSlice({

    name: 'cart',        //名字

    initialState:{       //存放数据

        cart: storage.getStorage('cart')

    },

    reducers: {  // 把reducers和actions合并在一起了

        // 商品加入购物车

        addCart(state,{ payload }){

            // 判断当前商品在购物车中是否存在

            const idx = state.cart.findIndex(item => item.id === payload.id)

            if(idx !== -1){  //证明当前商品在购物车中存在

                state.cart[idx].num += 1

            }else{

                state.cart.push(payload)

            }

            // 本地存储

            storage.setStorage('cart',state.cart)

        },

        //修改购物车商品的状态

        changeState(state,{ payload : id}){

            // 根据下标找下标

            const idx = state.cart.findIndex(item => item.id === id)

            // 更改状态

            state.cart[idx].checked = !state.cart[idx].checked

            // 本地存储

            storage.setStorage('cart',state.cart)

        },

        // 全选

        chooseAll(state,{ payload : checked }){

            state.cart.forEach(item => {

                item.checked = checked

            })

            // 本地存储

            storage.setStorage('cart',state.cart)

        },

        //修改商品的数量

        changeNum(state,{payload}){

            // 根据id找下标

            const idx = state.cart.findIndex(item => item.id === payload.id)

           

            switch(payload.type){

                case 'addNum':  //点击的是加号按钮

                    state.cart[idx].num++

                    break;

                case 'descNum':  //点击的是减号按钮

                    state.cart[idx].num > 1 && state.cart[idx].num--

                    break;

                default:

                    state.cart[idx].num = payload.num * 1

            }

            // 本地存储

            storage.setStorage('cart',state.cart)

        },

        // 删除当前商品

        delGoods(state,{payload : id}){

            // 根据id找下标

            const idx = state.cart.findIndex(item => item.id === id)

            // 删除当前商品

            state.cart.splice(idx,1)

            // 本地存储

            storage.setStorage('cart',state.cart)

        },

        // 删除选中商品

        delChoose(state){

            state.cart = state.cart.filter(item => item.checked === false)

            // 本地存储

            storage.setStorage('cart',state.cart)

        }

    }

})

// 写一个reducer就需要导出来一个

export const {

    addCart,

    changeState,

    chooseAll,

    changeNum,

    delGoods,

    delChoose

} = cart.actions

export default cart

5. 在store文件夹中,创建一个index.js文件

import { configureStore } from "@reduxjs/toolkit";

import cart from "./modules/cart";     //导入创建modules中的文件

// 创建store

const store = configureStore({

    reducer : cart.reducer

})

export default store

6.在index.js组件内导入store进行使用

import React from 'react';

import ReactDOM from 'react-dom/client';

import { RouterProvider } from 'react-router-dom'

import router from './router';

import { Provider } from 'react-redux'

import store from './store';

import './css/index.css';

const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(

  <React.StrictMode>

    {/* 使用Provider包裹根组件,挂载store,这样每个组件都可以拿到store */}

    <Provider store={store}>

      <RouterProvider router={router}/>

    </Provider>

  </React.StrictMode>

);

7.在list文件中

import React,{ useEffect,useState } from 'react'

import { useNavigate } from 'react-router-dom'

import axios from 'axios'

import { useDispatch } from 'react-redux'

import { addCart } from '../../store/modules/cart'

import './index.scss'


 

export default function List() {

  const navigate = useNavigate()

  const [list, setlist] = useState([])

  // 派发action的

  const dispatch = useDispatch()

  // 封装获取商品列表数据的方法

  const getList = async () => {

    const { data } = await axios.get('/data.json')

    setlist(data)

  }

  // 商品加入购物车

  const addGppds = goods => {

    dispatch(addCart({...goods, num: 1, checked: false}))

  }

  // 封装渲染商品列表的方法

  const renderList = () => (

    list.map((item,index)=>(

      <li key={index}>

        <div className="img-box">

          <img src={"/imgs/"+item.img} alt="" />

        </div>

        <div className="goods-info">

          <div className="goods-title">{item.title}</div>

          <div className="goods-info-footer">

            <div className="goods-price">{item.price}</div>

            <div className="add-cart" onClick={ () => addGppds(item) }>加入购物车</div>

          </div>

        </div>

      </li>

    ))

  )

  useEffect(()=>{

    getList()

  },[])

  return (

    <div className="goods-list">

      <div className="goods-list-content">

        <div className="go-cart" onClick={() => navigate('/cart')}>去购物车</div>

        <ul className="list">{ renderList() }</ul>

      </div>

    </div>

  )

}

8.在Cart文件中

import React,{ useMemo } from 'react'

import { useNavigate } from 'react-router-dom'

import { useSelector,useDispatch } from 'react-redux'  //useSelector:获取store模块中保存的数据

import { changeState,chooseAll,changeNum,delGoods,delChoose  } from '../../store/modules/cart'

import './index.scss'

export default function Cart() {

    const navigate = useNavigate()

    // 获取到redux中的数据

    const cart = useSelector(store => store.cart)

    const dispatch = useDispatch()

    // 全选按钮的状态

    const checkedAll = useMemo(() => cart.every(item => item.checked))

    // 手动修改购物车商品的数量

    const updateNum = (ev,id) => {

        if(!isNaN(ev.target.value)){

            dispatch( changeNum( { type:'changeNum', id: id, num : ev.target.value } ) )

        }else{

            dispatch( changeNum( { type:'changeNum', id: id, num : 1 } ) )

        }

       

    }

    // 失去焦点的时候触发

    const blur = (ev,id) => {

        ev.target.value == 0 && dispatch( changeNum( { type:'changeNum', id, num:1} ) )

    }

    // 计算当前选中商品的总价钱

    const totalPrice = useMemo(()=> {

        return cart.filter(item => item.checked).reduce((num,item) => num + item.price * item.num,0)

    })

    // 计算选中商品的总数量

    const totalCount = useMemo(() => {

        return cart.filter(item => item.checked).reduce((num,item) => num + item.num,0)

    })

    // 计算结算按钮的状态

    const settlementState = useMemo(() => cart.some(item => item.checked))

    // 封装渲染购物车列表的方法

    const renderCart = () => (

        cart.map(item => (

            <li key={ item.id }>

                <div className="checkbox">

                    <input type="checkbox" checked={ item.checked } onChange={ () => dispatch( changeState(item.id) ) } />

                </div>

                <div className="goods-info">

                    <div className="img-box">

                        <img src={"/imgs/" + item.img} alt="" />

                    </div>

                    <div className="goods-introduce">{ item.title }</div>

                </div>

                <div className="goods-price">¥{ (item.price).toFixed(2) }</div>

                <div className="goods-controler">

                    <div

                        className={ item.num > 1 ? "desc" : "desc disabled" }

                        onClick={ () => dispatch( changeNum({ type:'descNum', id: item.id }) ) }

                    >-</div>

                    <div className="input-wrapper">

                        <input type="text" value={ item.num } onChange={ ev => updateNum(ev,item.id) } onBlur={ ev => blur(ev,item.id) } />

                    </div>

                    <div className="add" onClick={ () => dispatch( changeNum({ type: 'addNum', id: item.id}) ) }>+</div>

                </div>

                <div className="goods-total">¥{ (item.price * item.num).toFixed(2) }</div>

                <div className="del-btn" onClick={() => dispatch(delGoods(item.id))}>删除</div>

            </li>

        ))

    )

   

    return (

        <div className="cart-wrapper">

            <div className="cart-content-wrapper">

                <div className="cart-title">

                    <h3>购物车</h3>

                    <div className="go-list" onClick={()=>navigate(-1)}>返回商品列表</div>

                </div>

                {

                    cart.length ?

                    <>

                        <div className="cart-list">

                        <li>

                            <div className="checkbox">

                            <input type="checkbox" />

                            </div>

                            <div className="goods-info-title">商品信息</div>

                            <div className="goods-price-title">单价</div>

                            <div className="goods-num-title">商品数量</div>

                            <div className="goods-total-title">金额</div>

                            <div>操作</div>

                        </li>

                        { renderCart() }

                        </div>

                        <div className="footer-wrapper">

                        <div className="left-box">

                            <label>

                            全选:<input type="checkbox" checked={checkedAll} onChange={ ev => dispatch( chooseAll(ev.target.checked) ) }/>

                            </label>

                            <div className="del-choose-btn" onClick={()=>dispatch(delChoose())}>删除</div>

                        </div>

                        <div className="right-box">

                            <div className="choose-goods-total">

                            <span>已选商品</span>

                            <span>{totalCount}</span>件

                            </div>

                            <div className="total-price">合计:<span>{ totalPrice.toFixed(2) }</span></div>

                            <div className={ settlementState ? "settlement-btn active" : "settlement-btn disabled" }>结算</div>

                        </div>

                        </div>

                    </>

                    :

                    <div className="empty-cart">

                        亲, 您还没有选购任何商品<router-link to="/list">赶快去购物吧!</router-link>

                    </div>

                }

            </div>

        </div>

    )

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值