很久没更新博客了,最近要用到react,再来跟大家分享一个redux案例吧。

 [
{"id": 1, "title": "iPad 4 Mini", "price": 500.01, "inventory": 2},
{"id": 2, "title": "H&M T-Shirt White", "price": 10.99, "inventory": 10},
{"id": 3, "title": "Charli XCX - Sucker CD", "price": 19.99, "inventory": 5}
]

这是购物车里面的数据

 import _products from './products.json' //把json引进来

 const TIMEOUT = 100

 export default {
getProducts: (cb, timeout) => setTimeout(() => cb(_products), timeout || TIMEOUT), //初始化产品
buyProducts: (payload, cb, timeout) => setTimeout(() => cb(), timeout || TIMEOUT)
}
//1:得到产品明细 (延迟) 2:购买产品

下面是购物车的操作

 import shop from '../api/shop'
import * as types from '../constants/ActionTypes' const receiveProducts = products => ({
type: types.RECEIVE_PRODUCTS,
products: products
}) export const getAllProducts = () => dispatch => {
shop.getProducts(products => {
dispatch(receiveProducts(products))
})
} //得到所有产品 从json里里面 const addToCartUnsafe = productId => ({
type: types.ADD_TO_CART,
productId //得到dispatch发送的数据
}) export const addToCart = productId => (dispatch, getState) => {
if (getState().products.byId[productId].inventory > 0) {
dispatch(addToCartUnsafe(productId))
}
} //增加产品 只有库存大于0时 export const checkout = products => (dispatch, getState) => {
const { cart } = getState() dispatch({
type: types.CHECKOUT_REQUEST
})
shop.buyProducts(products, () => {
dispatch({
type: types.CHECKOUT_SUCCESS,
cart
}) //当有买入或卖出时都会checkout
// Replace the line above with line below to rollback on failure:
// dispatch({ type: types.CHECKOUT_FAILURE, cart })
})
}

需要知道actiontypes,下面是actiontype时文件

 export const ADD_TO_CART = 'ADD_TO_CART'
export const CHECKOUT_REQUEST = 'CHECKOUT_REQUEST'
export const CHECKOUT_SUCCESS = 'CHECKOUT_SUCCESS'
export const CHECKOUT_FAILURE = 'CHECKOUT_FAILURE'
export const RECEIVE_PRODUCTS = 'RECEIVE_PRODUCTS'

下面展示产品的逻辑

 import { combineReducers } from 'redux'
import { RECEIVE_PRODUCTS, ADD_TO_CART } from '../constants/ActionTypes' const products = (state, action) => {
switch (action.type) {
case ADD_TO_CART:
return {
...state,
inventory: state.inventory - 1
}
default:
return state
}
} //往购物车里面添加一个 库存就会减少1个 注意es6语法 const byId = (state = {}, action) => {
switch (action.type) {
case RECEIVE_PRODUCTS:
return {
...state,
...action.products.reduce((obj, product) => {
obj[product.id] = product
return obj
}, {})
} // 重新初始化购物车
default:
const { productId } = action
if (productId) {
return {
...state,
[productId]: products(state[productId], action)
}
}
return state
}
} const visibleIds = (state = [], action) => {
switch (action.type) {
case RECEIVE_PRODUCTS:
return action.products.map(product => product.id)
default:
return state
}
} export default combineReducers({
byId,
visibleIds
}) //合并reducer export const getProduct = (state, id) =>
state.byId[id] export const getVisibleProducts = state =>
state.visibleIds.map(id => getProduct(state, id)) //得到visible的产品

下面再就是购物车的

 import {
ADD_TO_CART,
CHECKOUT_REQUEST,
CHECKOUT_FAILURE
} from '../constants/ActionTypes' const initialState = {
addedIds: [],
quantityById: {}
} const addedIds = (state = initialState.addedIds, action) => {
switch (action.type) {
case ADD_TO_CART:
if (state.indexOf(action.productId) !== -1) {
return state
}
return [ ...state, action.productId ]
default:
return state
}
} //如果已添加的id没有这个 就可以添加 const quantityById = (state = initialState.quantityById, action) => {
switch (action.type) {
case ADD_TO_CART:
const { productId } = action
return { ...state,
[productId]: (state[productId] || 0) + 1
} // 往购物车添加商品 没有就是0
default:
return state
}
} export const getQuantity = (state, productId) =>
state.quantityById[productId] || 0 export const getAddedIds = state => state.addedIds const cart = (state = initialState, action) => {
switch (action.type) {
case CHECKOUT_REQUEST:
return initialState
case CHECKOUT_FAILURE:
return action.cart
default:
return {
addedIds: addedIds(state.addedIds, action),
quantityById: quantityById(state.quantityById, action)
}
}
} export default cart

index.js

 import { combineReducers } from 'redux'
import cart, * as fromCart from './cart'
import products, * as fromProducts from './products' export default combineReducers({
cart,
products
}) const getAddedIds = state => fromCart.getAddedIds(state.cart)
const getQuantity = (state, id) => fromCart.getQuantity(state.cart, id)
const getProduct = (state, id) => fromProducts.getProduct(state.products, id) //方法调用 export const getTotal = state =>
getAddedIds(state)
.reduce((total, id) =>
total + getProduct(state, id).price * getQuantity(state, id),
0
)
.toFixed(2) //计算总价 export const getCartProducts = state =>
getAddedIds(state).map(id => ({
...getProduct(state, id),
quantity: getQuantity(state, id) //得到购物车产品和数量
}))

cart.js

 import React, { PropTypes } from 'react'
import Product from './Product' const Cart = ({ products, total, onCheckoutClicked }) => {
const hasProducts = products.length > 0
const nodes = hasProducts ? (
products.map(product =>
<Product
title={product.title}
price={product.price}
quantity={product.quantity}
key={product.id} //product组建 产品的title 数量 价格
/>
)
) : (
<em>Please add some products to cart.</em> //无产品时提示
) return (
<div>
<h3>Your Cart</h3>
<div>{nodes}</div>
<p>Total: ${total}</p>
<button onClick={onCheckoutClicked}
disabled={hasProducts ? '' : 'disabled'}> //购物车没产品时不能点击
Checkout
</button>
</div>
)
} Cart.propTypes = {
products: PropTypes.array,
total: PropTypes.string,
onCheckoutClicked: PropTypes.func
} export default Cart
Contact GitHub API Training Shop Blog About

cartcontainer.js

 import React, { PropTypes } from 'react'
import { connect } from 'react-redux'
import { checkout } from '../actions'
import { getTotal, getCartProducts } from '../reducers'
import Cart from '../components/Cart' const CartContainer = ({ products, total, checkout }) => (
<Cart
products={products}
total={total}
onCheckoutClicked={() => checkout(products)} />
) CartContainer.propTypes = {
products: PropTypes.arrayOf(PropTypes.shape({
id: PropTypes.number.isRequired,
title: PropTypes.string.isRequired,
price: PropTypes.number.isRequired,
quantity: PropTypes.number.isRequired
})).isRequired,
total: PropTypes.string,
checkout: PropTypes.func.isRequired
} const mapStateToProps = (state) => ({
products: getCartProducts(state), //这里得到得到的产品 就是上面的参数
total: getTotal(state) //总价也一样
}) export default connect(
mapStateToProps,
{ checkout }
)(CartContainer)

product.js

 import React, { PropTypes } from 'react'

 const Product = ({ price, quantity, title }) => (
<div>
{title} - ${price}{quantity ? ` x ${quantity}` : null} //有数量就算出总价
</div>
) Product.propTypes = {
price: PropTypes.number,
quantity: PropTypes.number,
title: PropTypes.string
} export default Product

productItem.js

 import React, { PropTypes } from 'react'
import Product from './Product' const ProductItem = ({ product, onAddToCartClicked }) => (
<div style={{ marginBottom: 20 }}>
<Product
title={product.title}
price={product.price} />
<button
onClick={onAddToCartClicked}
disabled={product.inventory > 0 ? '' : 'disabled'}> // 能否添加购物车
{product.inventory > 0 ? 'Add to cart' : 'Sold Out'} //有库存 无库存就时soldout
</button>
</div>
) ProductItem.propTypes = {
product: PropTypes.shape({
title: PropTypes.string.isRequired,
price: PropTypes.number.isRequired,
inventory: PropTypes.number.isRequired
}).isRequired,
onAddToCartClicked: PropTypes.func.isRequired
} export default ProductItem

productlist.js

 import React, { PropTypes } from 'react'

 const ProductsList = ({ title, children }) => (
<div>
<h3>{title}</h3>
<div>{children}</div>
</div>
) ProductsList.propTypes = {
children: PropTypes.node,
title: PropTypes.string.isRequired
} export default ProductsList

productcontainer.js

 import React, { PropTypes } from 'react'
import { connect } from 'react-redux'
import { addToCart } from '../actions'
import { getVisibleProducts } from '../reducers/products'
import ProductItem from '../components/ProductItem'
import ProductsList from '../components/ProductsList' const ProductsContainer = ({ products, addToCart }) => (
<ProductsList title="Products">
{products.map(product =>
<ProductItem
key={product.id}
product={product}
onAddToCartClicked={() => addToCart(product.id)} /> //这就是 children
)}
</ProductsList>
) ProductsContainer.propTypes = {
products: PropTypes.arrayOf(PropTypes.shape({
id: PropTypes.number.isRequired,
title: PropTypes.string.isRequired,
price: PropTypes.number.isRequired,
inventory: PropTypes.number.isRequired
})).isRequired,
addToCart: PropTypes.func.isRequired
} const mapStateToProps = state => ({
products: getVisibleProducts(state.products) //products的来源
}) export default connect(
mapStateToProps,
{ addToCart }
)(ProductsContainer)

app.js

 import React from 'react'
import ProductsContainer from './ProductsContainer'
import CartContainer from './CartContainer' const App = () => (
<div>
<h2>Shopping Cart Example</h2>
<hr/>
<ProductsContainer />
<hr/>
<CartContainer />
</div>
) export default App

到这里应该差不多看明白了,组件还是很容易看的,主要是action之间的衔接确实。。。

index.html

 import React from 'react'
import { render } from 'react-dom'
import { createStore, applyMiddleware } from 'redux'
import { Provider } from 'react-redux'
import createLogger from 'redux-logger'
import thunk from 'redux-thunk'
import reducer from './reducers'
import { getAllProducts } from './actions'
import App from './containers/App' const middleware = [ thunk ];
if (process.env.NODE_ENV !== 'production') {
middleware.push(createLogger());
} const store = createStore(
reducer,
applyMiddleware(...middleware)
) store.dispatch(getAllProducts()) //初始化产品 render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)

在我看来 redux的精华就是reducers,这点也是很难掌握的,组件到比较容易,今后多多研究reducer和action。

用redux构建购物车的更多相关文章

  1. react+redux构建淘票票首页

    react+redux构建淘票票首页 描述 在之前的项目中都是单纯的用react,并没有结合redux.对于中小项目仅仅使用react是可以的:但当项目变得更加复杂,仅仅使用react是远远不够的,我 ...

  2. Redux初见

    说到redux可能我们都先知道了react,但我发现,关于react相关的学习资料很多,也有各种各样的种类,但是关于redux简单易懂的资料却比较少. 这里记录一下自己的学习理解,希望可以简洁易懂,入 ...

  3. Redux状态管理方法与实例

    状态管理是目前构建单页应用中不可或缺的一环,也是值得花时间学习的知识点.React官方推荐我们使用Redux来管理我们的React应用,同时也提供了Redux的文档来供我们学习,中文版地址为http: ...

  4. Redux生态系统

    生态系统 Redux 是一个体小精悍的库,但它相关的内容和 API 都是精挑细选的,足以衍生出丰富的工具集和可扩展的生态系统. 如果需要关于 Redux 所有内容的列表,推荐移步至 Awesome R ...

  5. ApacheCN Asp.NET 译文集 20211126 更新

    ASP.NET Core2 基础知识 零.前言 一.搭建舞台 二.控制器 三.视图 四.模型 五.验证 六.路由 七.RestBuy 八.添加功能.测试和部署 ASP.NET Core3 和 Angu ...

  6. Jquery easyui 教程

            Jquery easyui教程                 目  录 1基本拖放... 4 2构建购物车型拖放... 5 3创建课程表... 8 4菜单和按钮Menu and Bu ...

  7. 初识React-Redux之粗暴理解入门

    权当暂记 日后再行补充完善,若有阅读者,请翻到下文黄色标题'从这里开始'起阅读. Rudex在我看来最本质做的事情就是将所有的State属性统一存储(一个属性就是一个注册到store的Reducer) ...

  8. mvp在flutter中的应用

    mvp模式的优点mvp模式将视图.业务逻辑.数据模型隔离,使用mvp模式,能使复杂的业务逻辑变得更加清晰,使代码更具有灵活性和扩展性,正是这些优点,使mvp模式广泛应用于原生开发中. flutter使 ...

  9. Jquery easyui教程

    目  录 1基本拖放.......................................................................................... ...

随机推荐

  1. 使用C#开发ActiveX控件(新)

    前言 ActiveX控件以前也叫做OLE控件,它是微软IE支持的一种软件组件或对象,可以将其插入到Web页面中,实现在浏览器端执行动态程序功能,以增强浏览器端的动态处理能力.通常ActiveX控件都是 ...

  2. Metrics-Java版的指标度量工具之二

    接上<Metrics-Java版的指标度量工具之一> 4.       Histograms Histograms主要使用来统计数据的分布情况,最大值.最小值.平均值.中位数,百分比(75 ...

  3. 原创教程:《metasploit新手指南》介绍及下载

    原创教程:<metasploit新手指南>介绍及下载 1.1 作者简介 这份教程并不是“玄魂工作室”原创,但是我还是要力推给大家.相比那些一连几年都在问“我怎么才能入门”的人而言,我们更欣 ...

  4. ubuntu 安装 axel

    Axel 通过打开多个 HTTP/FTP 连接来将一个文件进行分段下载,从而达到加速下载的目的.对于下载大文件,该工具将特别有用. 安装:sudo apt-get install axel 一般使用: ...

  5. 《OOC》笔记(0)——为何要看这本书

    <OOC>笔记(0)——为何要看这本书 <OOC>全名是<Object-oriented Programming with ANSI-C>,作者Axel-Tobia ...

  6. Flume日志采集系统——初体验(Logstash对比版)

    这两天看了一下Flume的开发文档,并且体验了下Flume的使用. 本文就从如下的几个方面讲述下我的使用心得: 初体验--与Logstash的对比 安装部署 启动教程 参数与实例分析 Flume初体验 ...

  7. [Spring框架]Spring 事务管理基础入门总结.

    前言:在之前的博客中已经说过了数据库的事务, 不过那里面更多的是说明事务的一些锁机制, 今天来说一下Spring管理事务的一些基础知识. 之前的文章: [数据库事务与锁]详解一: 彻底理解数据库事务一 ...

  8. ngResource提交json数据如何带参数

    ngResource提交json数据如何带参数 直接使用ngResource和REST服务接口交互可以让程序显得简洁,前提是配置好跨域和OPTIONS请求的支持,与此同时,如果需要带些额外的参数,有两 ...

  9. scrollview 中嵌套多个listview的最好解决办法

    在scrollview中嵌套多个listview的显示问题. 只需要调用如下的方法传入listview和adapter数据即可. /** * 动态设置ListView组建的高度 */ public s ...

  10. Lookup 组件异常

    Lookup组件有两个数据源,一个是上流组件的输出,一个是组件lookup的数据源,这个数据源是在Connection选项卡中进行配置.在开发package的过程中,我发现一个异常,当Lookup数据 ...