引用react-redux目录结构
actions/actionType.js
export default {
CART_AMOUNT_INCREACE: 'CART_AMOUNT_INCREACE',
CART_AMOUNT_DECREACE: 'CART_AMOUNT_DECREACE',
ADD_UNDERLINE: 'ADD_UNDERLINE'
}
actions/cart.js
// action 有两种写法
// 第一种写成一个对象,这是标准的action,但是问题是不方便传递动态参数,比如id那里写死了
// export const increace = (id) => {
// return {
// type: actionType.CART_AMOUNT_INCREACE,
// payload: {
// id:123
// }
// }
// }
import actionType from './actionType'
// 实际中常用的方式,actionCreator,它是一个方法,返回一个对象,这个对象才是真正的action
export const increace = (id) => {
return {
type: actionType.CART_AMOUNT_INCREACE,
payload: {
id
}
}
}
export const decreace = (id) => {
return {
type: actionType.CART_AMOUNT_DECREACE,
payload: {
id
}
}
}
export const underline = (id) => {
return {
type: actionType.ADD_UNDERLINE,
payload: {
id
}
}
}
reducers/cart.js
// 为了避免actionType重复,,所以一般都会把actionType放在一个文件里进行管理,也可以避免写错actonType
import actionType from '../actions/actionType'
// 对于这个购物车,这里有一个初始化的状态
const initState = [{
id: 1,
price: 88,
title: '哈哈',
amount: 10,
completed: false
}, {
id: 2,
price: 188,
title: 'jieke',
amount: 13,
completed: false
}]
// 创建购物车的reducer,reducer的固定写法是两个参数,第一个是state,第二个是action
export default (state = initState, action) => {
// 根据不同的action。type,做不同的处理,每次返回新的state,返回的类型要一样
switch (action.type) {
case actionType.CART_AMOUNT_INCREACE:
return state.map((item) => {
if (item.id === action.payload.id) {
item.amount += 1
}
return item;
})
case actionType.CART_AMOUNT_DECREACE:
return state.map((item) => {
if (item.id === action.payload.id) {
item.amount -= 1
}
return item;
})
case actionType.ADD_UNDERLINE:
return state.map((item) => {
if (item.id === action.payload.id) {
console.log(item.completed)
item.completed = !item.completed
}
return item;
})
// 一定要有default,当actionType不对的时候,不做处理
default:
return state
}
}
reducers/index.js
// 实际中,由于只有单一的store但是状态会有多个分类,所以需要划分reducer,createStore的参数又只接收一个
// reducer,所以,redux提供了合并的方法,combineReducers,不要手动合并
import { combineReducers } from 'redux'
// 引入cart reducer,如果有多个,继续引入
import cart from './cart'
// 导出合并的 reducer
export default combineReducers({
// 把多个reducer,作为combineReducers对象参数传入,在外部就可以通过store.getState().cart来获取到cartReducer里面的state
cart
})
components/CartList/index.js
import React, { PureComponent } from 'react'
// connect 执行后是一个高阶组件
import { connect } from 'react-redux'
// 导入actionCreators
import { increace, decreace, underline } from '../../actions/cart'
class CartList extends PureComponent {
render() {
return (
<table>
<thead>
<tr>
<th>id</th>
<th>商品名称</th>
<th>价格</th>
<th>数量</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{/* {this.props.Arrcartlist} */}
{
this.props.Arrcartlist.map(item => {
return (
// style={{ textDecoration: item.completed ? 'line-through' : 'none' }}
<tr key={item.id} style={{ textDecoration: item.completed ? 'line-through' : 'none' }}>
<td>{item.id}</td>
<td>{item.title}</td>
<td>{item.price}</td>
<td><button onClick={this.props.decreace.bind(this, item.id)}>-</button>
{item.amount}
<button onClick={this.props.increace.bind(this, item.id)}> +</button>
</td>
<td><button onClick={this.props.underline.bind(this, item.id)}>下划线</button></td>
</tr>
)
})
}
</tbody>
</table >
)
}
}
// mapStateToProps,这里的state实际上就是store.getState()的值
const mapState = (state) => {
// 这里return什么,就可以通过this.props获取
return {
Arrcartlist: state.cart
}
}
// mapDispatchToProps
// const mapDispatchToProps=dispatch=>{
// return {
// add:(id)=>dispatch(increace),
// reducer:(id)=>dispatch(decreace(id))
// }
// }
// connect 方法有四个参数,常用前两个,
// 第一个参数是mapStateToProps,作用就是从store里吧state注入到当前组件的props上
// 第二个参数可以是mapDispatchToProps,这个作用就是把action生成的方法注入到当前组件的props上,一般来说没必要这样用
// 直接第二个参数传递一个对象,这里的对象就是actionCreators,只要传入了actionCreators,在组件内就可以
// 通过this.props.actionCreator来调用,这样,在调用之后,那个actionCreator就会自动帮你把内部的action dispatch出去
export default connect(mapState, { increace, decreace, underline })(CartList)
components/index.js
export { default as CartList } from './CartList'
store.js
// createStore 是redux提供的用于创建store的方法
import { createStore } from 'redux'
// 引入合并后的reducer
import rootReducer from './reducers'
// createStore 的第一个参数必须是一个reducer如果是多个,现在reducer目录下使用combineReducers合并之后在导入
export default createStore(rootReducer)
App.js
import React, { PureComponent } from 'react'
import { CartList } from './components'
export default class App extends PureComponent {
render() {
return (
<div>
<CartList />
</div>
)
}
}
index.js
import React from 'react'
import ReactDom from 'react-dom'
// provider是react-redux提供的一个组件
import { Provider } from 'react-redux'
import App from './App'
import store from './store'
ReactDom.render(
// 一般就直接把这个组件放在应用程序的最顶层,这个组件必须有一个store属性,这个store属性的值就是咋们创建的那个store
// 只要在最外层包裹了这个provider,那么所有的后代组件都可以使用Redux。connect做连接
<Provider store={store}>
<App />
</Provider>, document.getElementById('root')
)
效果图
异步action用法
使用中间件
安装redux-thunk-》引入thunk-》引入中间件-》createStore(applyMiddleware(thunk))
npm install redux-thunk --save
// createStore 是redux提供的用于创建store的方法
import { createStore,applyMiddleware } from 'redux'
// 引入中间件
import thunk from 'redux-thunk'
// 引入合并后的reducer
import rootReducer from './reducers'
// createStore 的第一个参数必须是一个reducer如果是多个,现在reducer目录下使用combineReducers合并之后在导入
export default createStore(rootReducer,applyMiddleware(thunk))
action里面使用
// 异步action,使用redux-thunk之后,就可以在actionCreator里return一个方法,这个方法的参数是dispatch
// export const decreaceAsnyc = (id) => {
// return (dispatch) => {
// setTimeout(() => {
// dispatch({
// type: actionType.CART_AMOUNT_DECREACE,
// payload: {
// id
// }
// })
// }, 2000)
// }
// }
//优雅写法(babel https://babeljs.io/官网可看)
export const decreaceAsnyc = (id) => dispatch => {
setTimeout(() => {
dispatch(decreace(id))
}, 2000)
}
组件中使用
//使用
<button onClick={this.props.decreaceAsnyc.bind(this, item.id)}>异步减</button>