入口文件 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
}
}