一:Redux快速上手
// 1.state:管理的数据初始状态 action:对象type 标记当前想要做什么样的修改
function reducer (state = {count:0},action){
// 数据不可变:基于原始状态生成一个新的状态
if(action.type==="INCREMENT"){
return{count:state.count + 1}
}
if(action.type==="DECREMENT"){
return{count:state.count - 1}
}
return state
}
// 2.
const store = Redux.createStore(reducer)
// 3.回调函数可以在每次State发生变化的时候自动执行
store.subscribe(()=>{
console.log("state变化了",store.getState())
document.getElementById("count").innerText = store.getState().count
})
// 4.
const inBtn = document.getElementById("increment")
inBtn.addEventListener("click",()=>{
// 增
store.dispatch({
type:"INCREMENT"
})
})
const dBtn = document.getElementById("decrement")
dBtn.addEventListener("click",()=>{
// 减
store.dispatch({
type:"DECREMENT"
})
})
// 5.
二:Redux与React-环境准备
三:Redux与React-实现counter
import {createSlice} from "@reduxjs/toolkit"
const counterStore = createSlice({
name:"counter",
// 初始化state
initialState{
count:0
},
// 修改状态的方法,同步方法 支持直接修改
reducers:{
inscrement(state){
state.count++
},
decrement(state){
state.count--
}
}
})
// 解构出来actionCreater函数
const {inscrement,decrement } = counterStore.actions
// 获取reducer
const reducer = counterStore.reducer
// 以按需导出的方式导出actionCreater
export {inscrement,decrement}
// 以默认导出的方式导出reducer
export default reducer
index.js
import {configureStore} from "@reduxjs/toolkit"
//导入子模块reducer
import counterReducer from "./modules/counterStore"
const store = configureStore({
reducer:{
counter:counterReducer
}
})
export default store
import {useDispatch,useSelector} from "react-redux"
// 导入actionCreater
import {inscrement,decrement } from "./store/modules/counterStore"
function App(){
const {count} = useSelector(state => state.counter)
const dispatch = useDispatch()
return(
<div className="App">
<button onClick={() => dispatch(decrement())}>-</button>
{count}
<button onClick={() => dispatch(inscrement())}>+</button>
</div>
)
}
四:Redux与React-提交action传参
五:Redux与React-异步状态操作
import {createSlice} from "@reduxjs/toolkit"
import axios from "axios"
const channelStore = createSlice({
name:"channel",
initialState:{
channelList:[]
},
reducers:{
setChannels(state,action){
state.channelList = action.payload
}
}
})
// 异步请求部分
const {setChannels} = channelStore.actions
const fetchChannlList = () =>{
return async (dispatch)=>{
const res = await axios.get("url")
dispatch(setChannels(res.data.data.channels))
}
}
export {fetchChannlList}
const reducer = channelStore.reducer
export default reducer
index.js
import {configureStore} from "@reduxjs/toolkit"
//导入子模块reducer
import counterReducer from "./modules/counterStore"
import channelReducer from "./modules/channelStore"
const store = configureStore({
reducer:{
counter:counterReducer
channel:channelReducer
}
})
export default store
六:Redux调试-devtools
七:美团案例
1.案例演示和环境准备
2.分类和商品列表渲染
npm run serve
run start
store-modules-takeaway.js
// 编写store
import {createSlice} from "@reduxjs/toolkit"
const foodsStore = createSlice({
name:"foods",
initialState:{
// 商品列表
foodList:[]
},
reducers:{
setFoodsList(state,action){
state.foodsList = action.payload
}
}
})
// 异步获取部分
const {setFoodsList} = foodsStore.actions
const fetchFoodsList =() =>{
return async (dispatch) =>{
// 编写异步逻辑
const res = await axios.get("http://localhost:3004/takeaway")
// 调用dispatch函数提交action
dispatch(setFoodsList(res.data))
}
}
export {fetchFoodsList}
export default reducer
index.js
import foodsReducer from "./modules/takeaway"
import {configureStore} from "@reduxjs/toolkit"
const store = configureStore({
reducer:{
foods:foodsReducer
}
})
export default store
index.js
// 注入 store
import {Provider} from "react-redux"
import store from "./store"
const root = createRoot(document.getElementById("root"))
root.render(
<Provider store = {store}>
<App />
</Provider>
)
App.js
import {useDispatch, useSelector} from "react-redux"
import {fetchFoodsList} from "./store/modules/takeaway"
// 触发action执行
// 1.useDispatch -> dispatch 2.actionCreater导入进来
// 3.useEffect
const dispatch = useDispatch()
useEffect (() => {
dispatch(fetchFoodsList())
},[dispatch])
// 获取foodsList渲染数据列表
// 1.useSelector
const {foodsList} = useSelector(state =>state.foods)
3.点击分类激活交互实现
// 菜单激活下标值
activeIndex:0
// 更改activeIndex
changeActiveIndex(state,action){
state.activeIndex = action.payload
}
const {setFoodsList, changeActiveIndex} = foodsStore.actions
export {changeActiveIndex}
index.js
import {changeActiveIndex} from "../../store/modules/takeaway"
const dispatch = useDispatch()
onClick={() => dispatch(changeActiveIndex(index))}
const {foodsList,activeIndex} = useSelector(state => state.foods)
activeIndex === index && "active"
4.商品列表切换显示
activeIndex === index && <FoodsCategory
key={item.tag}
// 列表标题
name={item.name}
// 列表商品
foods={item.foods}
/>
5.添加购物车实现
// 购物车列表
cartList:[]
// 添加购物车
addCart(state,action){
// 是否添加过 以action.payload.id去cartList中匹配
// 匹配到了 代表添加过
const item = state.cartList.find(item => item.id === action.payload.id)
if(item){
item.count++
}else{
state.cartList.push(action.payload)
}
const {setFoodsList,changeActiveIndex,addCart} = foodsStore.actions
}
export{fetchFoodsList,changeActiveIndex,addCart}
index.js
import {addCart} fron "../../../store/modules/takeaway"
const dispatch = useDispatch()
<span className="plus" onClick={()=>dispatch(addCart({
id,
picture,
name,
unit,
description,
food_tag_list,
month_saled,
like_ratio_desc,
price,
tag,
count
}))}></span>
6.添加区域功能实现
const {cartList} = useSelector(state=>state.foods)
// 计算总价
const totalPrice = cartList.reduce((a,c) => a+c.price*c.count,0)
{totalPrice.toFixed(2)}
<div className={classNames("icon",cartList.length > 0 && "fill")}>
{cartList.length > 0 && <div className="cartCornerMark">{cartList.length}</div>}
</div>
{cartList.length > 0 && <div className = "cartCornerMark">{cartList.length}</div>}
// 结算起送
{cartList.length > 0 ?(
<div className = "goToPreview">去结算</div>
) : (
<div className="minFee">1元起送</div>
)}
7.购物车列表功能实现
<div className={classNames("cartPanel","visible")}>
</div>
takeaway.js
// count增
increCount(state,action){
// 关键点:找到当前要修改谁的count id
const item = state.cartList.find(item=>item.id===action.payload.id)
item.count++
},
// count减
decreCount(state,action){
// 关键点:找到当前要修改谁的count id
const item = state.cartList.find(item=>item.id===action.payload.id)
item.count--
},
const {increCount,decreCount} = foodsStore.action
export{increCount,decreCount}
index.js
import {increCount,decreCount} from "../../store/modules/takeaway"
const dispatch = useDispatch()
// 数量组件
<Count
count={item.count}
onPlus={()=> dispatch(increCount({id:item.id}))}
onMinus={()=> dispatch(decreCount({id:item.id}))}
/>
takeaway.js
// count增
increCount(state,action){
// 关键点:找到当前要修改谁的count id
const item = state.cartList.find(item=>item.id===action.payload.id)
item.count++
},
// count减
decreCount(state,action){
// 关键点:找到当前要修改谁的count id
const item = state.cartList.find(item=>item.id===action.payload.id)
if(item.count === 0){
return
}
item.count--
},
// 清除购物车
clearCart(state){
state.cartList = []
}
const {increCount,decreCount,clearCart} = foodsStore.action
export{increCount,decreCount,clearCart}
index.js
import {clearCart} from "../../store/modules/takeaway"
<span className = "clearCart" onClick={() => dispatch(clearCart)} >
清空购物车
</span>
8.控制购物车显示和隐藏
// 控制购物车打开关闭的状态
const [visible, setVisible] = useState(false)
<div
className={classNames("cartOverlay",visible && "visible")}
onClick ={()=>setVisible(false)}
/>
<div onClick ={onShow} className={classNames("icon",cartList.length > 0 && "fill")}>
{cartList.length > 0 && <div className="cartCornerMark">{cartList.length}</div>}
</div>
const onShow=()=>{
if(cartList.length > 0){
setVisible(true)
}
}
<div
className={classNames("cartPanel",visible && "visible")}>
</div>