React学习笔记九——React-redux的使用详解

react-redux模型图

  • 所有的UI组件都应该包裹一个容器组件,他们是父子关系
  • 容器组件是真正和redux打交道的,里面可以随意的使用redux的api
  • UI组件中不能使用任何redux的api
  • 容器组件会传给UI组件:1.redux中所保存的状态;2.用于操作状态的方法
  • 容器组件给UI组件传递状态和操作状态的方法均通过props传递

在这里插入图片描述

react-redux核心知识点

1.利用connect创建一个容器组件连接UI组件和redux

import {connect} from 'react-redux'
export default connect(mapStateToProps,mapDispatchToProps)(UI组件名)

2.connect的第一个参数mapStateToProps

  • mapStateToProps函数返回的是一个对象
  • 返回的对象中的key就作为传递给UI组件props的key,value就作为传递给UI组件props的value
  • mapStateToProps用于传递redux中的状态
function mapStateToProps(state){
  return {
   count:state
  }
}

3.connect的第二个参数mapDispatchToProps

  • mapDispatchToProps函数返回的是一个对象
  • 返回的对象中的key就作为传递给UI组件props的key,value就作为传递给UI组件props的value
  • mapDispatchToProps用于传递redux中操作状态的方法
function mapDispatchToProps(dispatch){
  return{
    increment:(data) => dispatch(incrementAction(data)),
    decrement:(data) => dispatch(decrementAction(data)), 
    incrementAsync :(data,time) => dispatch(incrementActionAsync (data,time)), 
  }
}

4.index.js入口文件不需要再用store.subscribe进行检测刷新

  • react-redux内部可以自己检测到redux状态更改
 ...
 ReactDOM.render(<app/>,document....)
 
/*store.subscribe(() => {
 ReactDOM.render(<app/>,document....)
}) */

react-redux完整代码案例

我们接下来就用react-redux去改造上章用redux写的案例,下面是虽然把所有文件全部引入过来,但是改进时基本上只操作了容器组件(这里我把容器组件和其UI组件写在一个文件里,为了方便管理和维护)

效果图:
在这里插入图片描述

Count组件 (改动)

  • 在文件内加入容器组件,并暴露出去,之前的组件作为其UI组件,
  • 容器组件与redux交互,UI组件内部只调用容器组件传入的状态和方法
import React from "react";
import {connect} from 'react-redux'

//UI组件
class CountUI extends React.Component{
 state = {}
 increment = () => {
   const {value} = this.selectNumber
   this.props.increment(value*1)
 }
 dencrement= () => {
   const {value} = this.selectNumber
   this.props.decrement(value*1)
 }
 incrementIfOdd= () => {
   const {value} = this.selectNumber
   const {count} = this.props
   if(count % 2 !== 0){
      this.props.increment(value*1)
   }
 }
 incrementAscyn= () => {
   const {value} = this.selectNumber
   this.props.incrementAsync(value*1,500)
 }
 render(){
   return(
     <div>
       <h2>当前求和:{this.props.count}</h2>
       <select ref={c => this.selectNumber = c}>
         <option value="1">1</option>
         <option value="2">2</option>
         <option value="3">3</option>
       </select>&nbsp;
       <button onClick={this.increment}>+</button>&nbsp;
       <button onClick={this.dencrement}>-</button>&nbsp;
       <button onClick={this.incrementIfOdd}>当前总数为奇数+</button>&nbsp;
       <button onClick={this.incrementAscyn}>异步+</button>&nbsp;
     </div>
   )
 }
} 

//此时store仓库只关联了Count组件的reducer,所以redux中只有一个状态值,所以state就是count
//后面我们会讲到多个组件共享数据,到时候store会保存多个组件的reducer,我们会通过redux中一个api去合并所有的reducer产生的值到一个对象里
function mapStateToProps(state){
  return {
   count:state
  }
}

function mapDispatchToProps(dispatch){
  return{
    increment:(data) => dispatch(incrementAction(data)),
    decrement:(data) => dispatch(decrementAction(data)), 
    incrementAsync :(data,time) => dispatch(incrementActionAsync (data,time)), 
  }
}
//容器组件
export default connect(mapStateToProps,mapDispatchToProps)(CountUI)

store.js(未改动)

/*该文件专门用于暴露一个store对象,整个应用只有一个store对象*/

 import {createStore,applyMiddleware} from "redux"
 //引入为Count组件服务的reducer 
 import reducer from  "./reducers"
 //引入redux-thunk中间件,用于支持异步action
 import thunk from "redux-thunk" 
 
 export default createStore(reducer,applyMiddleware(thunk))

constant.js(未改动)

/* 该模块用于定义action对象中type类型的常量值,
便于管理和维护的同时,防止程序员单词写错*/

export const INCREMENT = "increment"
export const DECREMENT = "dencrement"

count_action.js (未改动)

/* 该文件专门为Coun组件生成的action对象;
action的值为对象是同步,为函数是异步*/
import {INCREMENT,DECREMENT} from './constant'
import store from './redux/store'

export const incrementAction = data => ({type:INCREMENT,data})

export const decrementAction = data => ({type:DECREMENT,data})

export const incrementActionAsync = (data,time) => {
  //返回一个函数,函数能开启异步任务
  return (dispatch) => {
     setTimeout(() => {
        dispatch(incrementAction(data))
     },time)
  }
}

count_reducer.js (未改动)

/* 1.该文件用于创建一个为Count组件服务的reducer,reducer的本质就是一个函数
2.reducer函数会传入两个参数:分别为:之前的状态(previousState),动作对象(action)
 */
 
 //redux初始化状态
import {INCREMENT,DECREMENT} from './constant'

const initState = 0 initState = {count:0}
export defaulr function countReducer(preState=initState,action){
  const {type,data} = action
  switch(type){
    case INCREMENT:
      return preState + data
    case DECREMENT:
      return preState - data
    default: 
      return preState      
  }
}

app.jsx(改动)

  • 实际没有改动代码,只是此时的Count 组件不是UI组件,而是容器组件
import React ,{Component} from 'react'
//引入容器组件
import Count from ./Count
import store from './redux/store'

export default class APP extends Component {
  render(){
    <div>
       <Count /> 
    </div>
  }
}

index.js入口文件(改动)

  • 利用react-redux中的provider方法给App下所有需要store的容器组件传入store,使容器组件与redux关联起来
  • 删除之前的检测改动,react-redux自动检测刷新
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import store from './store'
//会给App下所有需要store的容器组件传入store
import {provider} from 'react-redux'

ReactDOM.render(
<provider store={store}>
   <app/>
<provider/>
,document.getElementById('root'))

/*为了redux内部状态发生改变,就重新渲染组件,不用担心一个组件内部状态改变,其他组件会被渲染,因为diff算法,只会重新渲染状态更改的组件*/
/*store.subscribe(() => {
 ReactDOM.render(<app/>,document....)
}) */

容器组件简化版代码

  • mapDispatchToProps作为第二个参数可以写作一个对象
  • mapDispatchToProps对象的value值只需要调用action返回一个动作对象即可,react-redux会自动dispatch分发
import React from "react";
import {connect} from 'react-redux'

//UI组件
class CountUI extends React.Component{
  ...
} 


//容器组件
export default connect(
state => ({count:state}),
{ 
 increment:incrementAction, 
 decrement:decrementAction,
 incrementAsync:incrementActionAsync 
}
)(CountUI)
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端探险家

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值