使用react-redux改造redux应用中的购物车demo

入口文件 index.js:

import React from 'react'
import ReactDOM from 'react-dom'

import {Provider} from 'react-redux'

// 导入 counter 下面的仓库
// import store from './components/counter/store/store'

// 导入 cart-react-redux 下面的仓库
import store from './components/cart-react-redux/store/store'

// 导入根组件
import App from './App.jsx'

// 使用ReactDOM的render方法来渲染根组件
ReactDOM.render(
    <Provider store={store}>
        <App />
    </Provider>
    ,document.getElementById("root"))

index.jsx

import React, { Component } from "react";

import './Index.css'

import {HashRouter as Router,Link,Route,Switch,Redirect} from 'react-router-dom'

import GoodsList from './GoodsList'
import Cart from './Cart'
import NotFound from '../router/404'

import 'element-theme-default'

// 建立组件和仓库之间的关联关系
import {connect} from 'react-redux'

class Index extends Component {
  componentDidMount(){    //--------------页面刷新时存储已经勾选的商品列表数据
    window.onbeforeunload = () => {
      localStorage.setItem('GOODS',JSON.stringify(this.props.goodsList))
    }
  }

  render() {
    return (
      <Router>
        <h2 className="title">
         商城
          <p>
            <Link to="/goodslist">
              商品列表
            </Link>
            <Link to="/cart">
                购物车{this.props.count > 0 && <span>({this.props.count})</span>}
            </Link>
          </p>
        </h2>
        <div className="index-container">
          <Switch>
            <Route path="/goodslist" component={GoodsList} />
            <Route path="/cart" component={Cart} />
            <Redirect exact from='/' to="/goodslist"/>
            <Route component={NotFound} />
          </Switch>
        </div>
      </Router>
    );
  }
}

const mapStateToProps = state => {
  console.log("----Index-----")
  // 定义的一个内部函数
  const calcCount = () => {
    let totalCount = 0
    state.forEach(item => {
      totalCount += item.num
    })

    return totalCount
  } 

  return {
    count:calcCount(),
    goodsList:state
  }
}

export default connect(mapStateToProps,null)(Index)

index.css(与redux应用中的一样,此处省略)

goodsList.jsx

import React, { Component } from "react";

import { Button } from 'element-react'

import {asyncAddAction} from './store/actionCreators'

import {connect} from 'react-redux'

class GoodsList extends Component {
  constructor() {
    super();

    this.state = {
      fruitList: [
        {
          id: 10001,
          num: 1,
          url:
            "https://gss2.bdstatic.com/-fo3dSag_xI4khGkpoWK1HF6hhy/baike/w%3D268%3Bg%3D0/sign=4ad42080aecc7cd9fa2d33df013a4602/42a98226cffc1e176cf9b75c4790f603738de91d.jpg",
          name: "苹果",
          price: 5
        },
        {
          id: 10002,
          num: 1,
          url:
            "https://gss3.bdstatic.com/7Po3dSag_xI4khGkpoWK1HF6hhy/baike/w%3D268%3Bg%3D0/sign=607b103081d6277fe912353e1003780d/5d6034a85edf8db12c69f8ef0f23dd54574e74f2.jpg",
          name: "香蕉",
          price: 2.5
        },
        {
          id: 10003,
          num: 1,
          url:
            "https://gss1.bdstatic.com/-vo3dSag_xI4khGkpoWK1HF6hhy/baike/w%3D268%3Bg%3D0/sign=12aef9c102082838680ddb1280a2ce3c/8cb1cb1349540923e88531a09758d109b2de497b.jpg",
          name: "哈密瓜",
          price: 20
        },
        {
          id: 10004,
          num: 1,
          url:
            "https://gss1.bdstatic.com/9vo3dSag_xI4khGkpoWK1HF6hhy/baike/w%3D268%3Bg%3D0/sign=c708fc0ac41b9d168ac79d67cbe5d3b2/8601a18b87d6277f2fe15ced22381f30e824fc70.jpg",
          name: "榴莲",
          price: 35
        }
      ]
    };
  }

  render() {
    return <div>
        <ul>
            {this.state.fruitList.map(item=>{
                return <li key={item.id}>
                    <img src={item.url} alt=""/>
                    <p>{item.name}</p>
                    <p>{item.price}</p>
                    <Button onClick={() => this.props.asyncAddGoods(item)} style={{marginTop:10}} type="success">加入购物车</Button>
                </li>
            })}
        </ul>
    </div>;
  }
}

const mapDispatchToProps = dispatch => {
  return {
    asyncAddGoods(item){
      dispatch(asyncAddAction(item))
    }
  }
}

export default connect(null,mapDispatchToProps)(GoodsList)

cart.jsx

import React, { Component } from "react";

import { Table, Button, InputNumber, MessageBox } from "element-react";

// 建立当前Cart组件与Store的关联
import {connect} from 'react-redux'

// 导入 actionCreators
import {updateGoodsAction,deleteGoodsAction} from './store/actionCreators'

class Cart extends Component {
  constructor() {
    super();

    this.state = {
      columns: [
        {
          label: "名字",
          prop: "name"
        },
        {
          label: "图片",
          render: data => {
            return <img style={{ width: 100, height: 100 }} src={data.url} />;
          }
        },
        {
          label: "数量",
          render: data => {
            return (
              <InputNumber
                min={1}
                size="small"
                value={data.num}
                onChange={this.editGoods.bind(this, data.id)}
                defaultValue={data.num}
              />
            );
          }
        },
        {
          label: "单价",
          prop: "price"
        },
        {
          label: "总价",
          render: ({ num, price }) => {
            return <span>{num * price}</span>;
          }
        },
        {
          label: "操作",
          render: data => {
            return (
              <Button
                onClick={this.deleteGoods.bind(this, data.id)}
                type="danger"
              >
                删除
              </Button>
            );
          }
        }
      ],
    };
  }

  // 修改商品
  editGoods = (id, newNum) => {
    this.props.updateGoods({
      id,
      newNum
    })
  };

  // 删除商品
  deleteGoods = id => {
    MessageBox.confirm("确定删除该商品吗?", "提示", {
      type: "warning"
    })
      .then(() => {
        this.props.deleteGoods(id)
      })
      .catch(() => {});
  };

  render() {
    return (
      <div style={{ marginLeft: 5 }}>
        <Table
          style={{ width: "100%" }}
          columns={this.state.columns}
          data={this.props.goodsList}
        />
        <p>总价:{this.props.totalPrice}</p>
        <Button type="success">结算</Button>
      </div>
    );
  }
}

const mapDispatchToProps = dispatch => {
  return {
    updateGoods(item){
      dispatch(updateGoodsAction(item))
    },
    deleteGoods(id){
      dispatch(deleteGoodsAction(id))
    }
  }
}

export default connect(
  state => {
    const calcTotalPrice = () => {
      let totalPrice = 0
      state.forEach(item => {
        totalPrice += item.num * item.price
      })

      return totalPrice
    }

    return {
      goodsList:state,
      totalPrice:calcTotalPrice()
    }
  }
,mapDispatchToProps)(Cart)

store文件夹下:
store.js

import {createStore,applyMiddleware,compose } from 'redux'

import thunk from 'redux-thunk';

// 导入 reducers
import reducers from './reducers'

// 创建仓库并且导出
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(reducers, /* preloadedState, */ composeEnhancers(
    applyMiddleware(thunk)
))


// 没有集成调试工具的    
// const store = createStore(reducers,applyMiddleware(thunk))

export default store

reducers.js (抽取出actionType):

import {ADD_GOODS,UPDATE_GOODS,DELETE_GOODS} from './actionTypes'

// 去本地加载购物车中的商品列表
const goodsList = JSON.parse(localStorage.getItem('GOODS') || '[]')

export default function(state = goodsList,action){
    // console.log(action)
    switch (action.type) {
        case ADD_GOODS:
            const AddLIST = JSON.parse(JSON.stringify(state))
            const addGoods = AddLIST.find(item => item.id === action.goods.id)
            if (addGoods) {
                addGoods.num += action.goods.num
            } else {
                AddLIST.push(action.goods)
            }
            return AddLIST

        case UPDATE_GOODS:
            const UpdataList = JSON.parse(JSON.stringify(state))
            const updateGoods = UpdataList.find(item => item.id === action.goods.id)
            updateGoods.num = action.goods.newNum

            return UpdataList

        case DELETE_GOODS:
            const DELETEList = JSON.parse(JSON.stringify(state))
            const deleteIndex = DELETEList.findIndex(item => item.id === action.id)
            DELETEList.splice(deleteIndex,1)

            return DELETEList
    
        default:
            return state
    }
}

actionType.js

export const ADD_GOODS = 'ADD_GOODS'
export const UPDATE_GOODS = 'UPDATE_GOODS'
export const DELETE_GOODS = 'DELETE_GOODS'

actionCreator.js

import {ADD_GOODS,UPDATE_GOODS,DELETE_GOODS} from './actionTypes'

/**
 * 创建一个一个要触发的action对象
 */
export function addAction(item){
    // 返回的就是一个action对象
    return {
        type:ADD_GOODS,
        goods:item
    }
}

export function asyncAddAction(item){
    // dispatch 是等着异步操作完毕之后,再触发action用得着
    return dispatch => {
        setTimeout(() => {
            dispatch(addAction(item))
        }, 2000)
    }
}

export function updateGoodsAction(item){
    return {
        type:UPDATE_GOODS,
        goods:item
    }
}

export function deleteGoodsAction(id){
    return {
        type:DELETE_GOODS,
        id
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值