6-React Redux

## 一：Redux快速上手
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/e73be987-84a0-40e8-8ccc-8f5e6073f5fe.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/53dd7c39-212a-484a-83d6-8645de06ff23.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/5a75a563-da29-4094-8de6-16cd80d99974.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/189520f9-8f85-4e69-a456-4a38b1e2e610.png)
```java
// 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-环境准备
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/19cb4b41-c5e3-4f4a-bbee-e6ccc83d751e.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/fe5af1d9-fb18-4a3c-a9a3-b2a995554873.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/ee9bdcd0-a3e5-44ca-87e6-4882b97668ac.png)
## 三：Redux与React-实现counter
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/db6d67e0-13a1-4898-a199-ba2f20b33ad2.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/219c311c-942f-4fe4-825e-fee8c7407e31.png)
在counterStore.js中
```java
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
```java
import {configureStore} from "@reduxjs/toolkit"
//导入子模块reducer
import counterReducer from "./modules/counterStore"

const store = configureStore({
 reducer:{
    counter:counterReducer
 }
})
export default store
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/2e08cbfc-a2f3-4911-9c4e-67e74b24b760.png)
index.js
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/eb1111d9-a250-4e9f-a0bd-8fb1b3579cd9.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/ebfd3d85-be38-48a4-9ddb-48a9fe0a6abb.png)
App.js
```java
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>
  )
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/caf69751-f886-4d3d-a880-23d2dc84413b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/6d695bb7-3654-44cf-9876-1f2c5458009f.png)
## 四：Redux与React-提交action传参
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/97ca7e67-6b1c-453e-bb7b-7b0a5a660027.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/3b2884f0-b8e9-4356-b087-1e8959c6decf.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/a5e56321-dec8-4e88-8207-82902737db10.png)
## 五：Redux与React-异步状态操作
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/ff044bdc-38a6-4310-9749-bf9f2ed60794.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/82d99fd3-5190-4538-a141-23ae65e5bfbd.png)
channelStore.js
```java
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
```java
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
```
App.js
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/68b96f23-f890-4f3e-889a-83aedcac16ec.png)
## 六：Redux调试-devtools
## 七：美团案例
#### 1.案例演示和环境准备
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/b3202f4f-0b5f-4f50-b970-3b36a0cd149b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/2bd7abe9-1df5-4aa6-b15e-af72a0e4fa29.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/b6c68171-ef57-45b4-8a8b-50d5cdda5adc.png)
#### 2.分类和商品列表渲染
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/f38727ef-46e6-4300-8e8d-6ebe266337d3.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/768354d6-4407-45a6-99a9-62a4b7fcc501.png)
package.json
```java
npm run serve
```
```java
run start
```
store-modules-takeaway.js
```java
// 编写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
```java
import foodsReducer from "./modules/takeaway"
import {configureStore} from "@reduxjs/toolkit"

const store = configureStore({
 reducer:{
  foods:foodsReducer
 }
})
export default store
```
index.js
```java
// 注入 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
```java
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.点击分类激活交互实现
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/6ae4b2b0-8455-46f2-8447-064afad87b47.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/e1ce1bbf-c6bb-4ff5-93d4-79e271f8b51a.png)
index.js
```java
// 菜单激活下标值
activeIndex:0
// 更改activeIndex
changeActiveIndex(state,action){
  state.activeIndex = action.payload
}

const {setFoodsList, changeActiveIndex} = foodsStore.actions
export {changeActiveIndex}
```
index.js
```java
import {changeActiveIndex} from "../../store/modules/takeaway"
const dispatch = useDispatch()
onClick={() => dispatch(changeActiveIndex(index))}

const {foodsList,activeIndex} = useSelector(state => state.foods)
activeIndex === index && "active"
```
#### 4.商品列表切换显示
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/9aa7be14-87bc-4d76-8cfa-dfe9866c9995.png)
App.js
```java
activeIndex === index && <FoodsCategory
  key={item.tag}
   // 列表标题
  name={item.name}
   // 列表商品
  foods={item.foods}
  />
```
#### 5.添加购物车实现
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/84b891e7-8a20-4e98-afa0-92f524894c58.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/4662d02c-8a56-4e19-96fc-6e51d75440a4.png)
takeaway.js
```java
// 购物车列表
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
```java
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.添加区域功能实现
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/394f90d9-d604-4f8d-ba84-d68258174e5a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/88a6e852-8543-4e35-a40c-bcc82e68a25f.png)
index.js
```java
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.购物车列表功能实现
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/f364eb7e-c0ff-48f4-bfc8-b92332ab48b9.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/a3c29187-f63e-49a2-ae34-a18089a228aa.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/a6a43ec6-d61d-4ac3-8bd9-384b22dfc245.png)
index.js
```java
<div className={classNames("cartPanel","visible")}>
</div>
```
takeaway.js
```java
// 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
```java
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
```java
// 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
```java
import {clearCart} from "../../store/modules/takeaway"
<span className = "clearCart" onClick={() => dispatch(clearCart)} >
清空购物车
</span>
```
#### 8.控制购物车显示和隐藏
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3899383/bdfbd084-2315-44c7-bfb0-c2157b663693.png)
![uploading...0]()
index.js
```java
// 控制购物车打开关闭的状态
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>
```





```java

```