很久没更新博客了,最近要用到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. 【Win10 UWP】微信SDK基本使用方法和基本原理

    上回讲到,作为一个长期散播温暖,散播希望的小清新无公害WP开发者,继QQ SDK之后,又把UWP微信SDK这茬了结了,仅供学习交流. 1.安装微信SDK for UWP 微信官方此前明确说明短时间内暂 ...

  2. TclError: no display name and no $DISPLAY environment variable

    %matplotlib inline 或 %matplotlib notebook

  3. objective-c(内存管理)

    本文主要记录objective-c 内存管理的知识点: 1.objective-c的对象都是分配内存在堆上,与C的mallock和C++的new类似,只有int等系统变量分配内存在栈上: 2.obje ...

  4. 详解SQL集合运算

    以前总是追求新东西,发现基础才是最重要的,今年主要的目标是精通SQL查询和SQL性能优化. 本系列[T-SQL基础]主要是针对T-SQL基础的总结. [T-SQL基础]01.单表查询-几道sql查询题 ...

  5. 备忘: Install MODI for use with Microsoft Office 201x

    简介 Microsoft Office 2010 中删除了 Microsoft Office Document Imaging (MODI).本文提供了在计算机上安装 MODI 的步骤,还说明了重新获 ...

  6. Windbg用法详解

    工作空间 WinDBG的工作空间中保存了以下几种信息 调试会话状态: 包括断点,打开的源文件,用户定义的别名(alias)等. 调试器设置:包括符号文件路径,可执行映像文件路径,源文件路径,用I+/I ...

  7. HTTP学习笔记(五)

    目前,市场上流行有很多web服务器软件,每种服务器都有自己的特点.我们在开发的过程中,经常要和它们打交道,所以了解它们的工作原理也是很重要的. 几款比较流行的服务器 它们会做些什么? 第三篇中有这样的 ...

  8. InputStream与InputStreamReader的区别

    InputStream是字节流,多用于读取二进制数据 InputStreamReader是字符流,多用于读取文本文件.有不同的编码方式,如utf8等.可以在构造的时候指定编码方式. 例如,两者都有一个 ...

  9. Vuejs注意点

    1.多级联动的时候,前一级变的时候,首先要把后面级的内容清空,要不然用户可能把前一次后面级的选择和新的前一级的选择提交(即后边级的列表渲染出来了,单但用户没有选择,此时vue绑定的是上一次的数据). ...

  10. PHP面向对象05_接口与多态

    抽象类与接口 2014-9-2 9:14:32 摘要: 1.抽象类(abstract) 2.接口(interface) 3.多态的应用 1.抽象类(abstract) 特点: 1)抽象类使用abstr ...