React 初探 [九] redux react-redux 基本使用与counter 案例

完整代码地址 https://gitee.com/xiaozhidayu/my-react

redux

redux 理解

1、学习文档

     1).英文文档: https://redux.js.org/

     2).中文文档: http://www.redux.org.cn/

     3).Github: https://github.com/reactjs/redux

2、redux 是什么?

      1). redux 是一个独立专门用于做状态管理的JS 库 (不是react 的插件库)

      2).他可以用在react angular vue 等项目中,但基本与react 配合使用

      3). 作用:集中管理react应用中多个组件共享的状态

3、redux 工作流程

4、什么情况下需要使用redux

     1)、总体原则,能不用就不用,如果不用 项目写起来比较吃力才用(!!!其实在实际项目开发中基本都需要用)

     2)、某个组件的状态需要共享

     3)、某个状态需要在任何地方都可以拿到

     4)、一个组件需要改变全局状态

     5)、一个组件需要改变另外一个组件的状态

redux 核心API

1、createStore()

      ①作用:创建包含指定reducer 的 store 对象

      ② 编码:

           import {createStore} from 'redux'

           import counter from './reducers/counter'

           const store = createStore(counter)

2、store 对象

     ① 作用:redux 库最核心的管理对象

     ② 它内部维护着 : state      、   reducer 

     ③ 核心方法:getState()   、dispatch(action)、subscribe(listener)

     ④ 编码:store.getState()、 store.dispatch({type:'INCREMENT', number})、store.subscribe(render)

3、applyMiddleware

      ① 应用上基于redux 的中间件(插件库)

      ② 编码 :

 import {createStore, applyMiddleware} from 'redux'

import thunk from 'redux-thunk'  // redux异步中间件

const store = createStore(

  counter,

  applyMiddleware(thunk) // 应用上异步中间件

)

4、combineReducers()

      ① 作用:合并多个reducer 函数

      ② 编码:

  export default combineReducers({
  user,
  chatUser,
  chat
})

redux 的三个核心概念

1、action

      ①标识要执行行为的对象

      ②包含两个方面的属性

          a、type:标识属性,值为字符串,唯一,必要属性

          b、xxx :数据属性,值类型任意,可选属性 (可统一xxx 为 data,方便统一取数据)

      ③ 例子 :

    const action = {
          type: 'INCREMENT',
          data: 2
      }

     ④ Action Creator(创建Action的工厂函数)

     const increment = (number) => ({type: 'INCREMENT', data: number})

2、reducer

      ① 根据老的state 和 action ,产生新的state 的 纯函数

      ② 例子:

                  export default function counter(state = 0, action) {
                    switch (action.type) {
                      case 'INCREMENT':
                        return state + action.data
                      case 'DECREMENT':
                        return state - action.data
                      default:
                        return state
                    }
                  }

       ③注意:

            a、返回一个新的状态

            b、不要修改原来的状态

3、store

      ①、将state,actionreducer联系在一起的对象

      ②、如何得到此对象?

        import {createStore} from 'redux'
        import reducer from './reducers'
        const store = createStore(reducer)

     ③、此对象的功能?

          getState(): 得到state
           dispatch(action): 分发action, 触发reducer调用, 产生新的state
           subscribe(listener): 注册监听, 当产生了新的state时, 自动调用

实践出真知 应用demo

// import React from 'react'
import React, { Component } from 'react'
import { INCREMENT, DECREMENT } from '../redux/action-types'
import * as actions from '../redux/actions.js'
import '../App.css'
class App extends Component {
  state = {
    count: 0,
  }
  increment = () => {
    //1、得到选择增加数量
    const number = this.select.value * 1
    //2、得到原本的count 状态 并计算新的count
    // const count = this.state.count + number
    //3、更新状态
    // this.setState({ count })
    //2、调用store 的方法更新状态
    this.props.store.dispatch(actions.increment(number))
  }
  decrement = () => {
    //1、得到选择增加数量
    const number = this.select.value * 1

    //2、得到原本的count 状态 并计算新的count
    // const count = this.state.count - number
    //3、更新状态
    // this.setState({ count })
    //2、调用store 的方法更新状态
    this.props.store.dispatch(actions.decrement(number))
  }
  incrementIfOdd = () => {
    //1、得到选择增加数量
    const number = this.select.value * 1
    //2、得到原本的count 状态
    // const count = this.state.count
    const count = this.props.store.getState()
    //3、判断 满足条件才更新状态
    if (count % 2 == 1) {
      // this.setState({ count: count + number })
      this.props.store.dispatch(actions.increment(number))
    }
  }
  incrementAsync = () => {
    //1、得到选择增加数量
    const number = this.select.value * 1
    //2、得到原本的count 状态 并计算新的count
    // const count = this.state.count
    //3、启动延时定时器 更新状态
    setTimeout(() => {
      // this.setState({ count: count + number })
      this.props.store.dispatch(actions.increment(number))
    }, 1000)
  }
  render() {
    // const { count } = this.state
    const count = this.props.store.getState()
    return (
      <div className="App">
        <p>click {count} times</p>
        <div>
          <select ref={(select) => (this.select = select)}>
            <option value="1">1</option>
            <option value="2">2</option>
            <option value="3">3</option>
          </select>
          &nbsp;&nbsp;
          <button onClick={this.increment}>+</button>&nbsp;&nbsp;
          <button onClick={this.decrement}>-</button>&nbsp;&nbsp;
          <button onClick={this.incrementIfOdd}>increment if odd</button>
          &nbsp;&nbsp;
          <button onClick={this.incrementAsync}>increment async</button>
        </div>
      </div>
    )
  }
}
// function App() {}

export default App

其他功能由 如下几个文件 分工完成

 

react-redux 

理解

redux 存在一些问题,因此应运而生了 react-redux

  1. reduxreact组件的代码耦合度太高
  2. 编码不够简洁

1)    一个react插件库
2)    专门用来简化react应用中使用redux

react-redux 将所有组件分为两大类

1)    UI组件
       a.    只负责 UI 的呈现,不带有任何业务逻辑
       b.    通过props接收数据(一般数据和函数)
       c.    不使用任何 Redux 的 API
       d.    一般保存在components文件夹下
2)    容器组件
       a.    负责管理数据和业务逻辑,不负责UI的呈现
       b.    使用 Redux 的 API
       c.    一般保存在containers文件夹下

相关API

1)    Provider
让所有组件都可以得到state数据

<Provider store={store}>
    <App />
  </Provider>

2)    connect() :用于包装 UI 组件生成容器组件

import { connect } from 'react-redux'
  connect(
    mapStateToprops,
    mapDispatchToProps
  )(Counter)


3)    mapStateToprops(): 将外部的数据(即state对象)转换为UI组件的标签属性

  const mapStateToprops = function (state) {
   return {
     value: state
   }
  }


4)    mapDispatchToProps()
      将分发action的函数转换为UI组件的标签属性
      简洁语法可以直接指定为actions对象或包含多个action方法的对象

应用demo

模拟了项目中的组件封装,UI 组件 和 容器组件分别放在 component 和 containers 文件夹下,主要代码如下:

// import React from 'react'
import React, { Component } from 'react'
import PropTypes from 'prop-types'
// import { connect } from 'react-redux'
// import { INCREMENT, DECREMENT } from '../redux/action-types'
// import { increment, decrement } from '../redux/actions.js'
import '../App.css'

export default class Counter extends Component {
  static propTypes = {
    count: PropTypes.number.isRequired,
    increment: PropTypes.func.isRequired,
    decrement: PropTypes.func.isRequired,
  }

  // state = {
  //   count: 0,
  // }
  increment = () => {
    //1、得到选择增加数量
    const number = this.select.value * 1
    //2、得到原本的count 状态 并计算新的count
    // const count = this.state.count + number
    //3、更新状态
    // this.setState({ count })
    //2、调用store 的方法更新状态
    // this.props.store.dispatch(actions.increment(number))
    this.props.increment(number)
  }
  decrement = () => {
    //1、得到选择增加数量
    const number = this.select.value * 1

    //2、得到原本的count 状态 并计算新的count
    // const count = this.state.count - number
    //3、更新状态
    // this.setState({ count })
    //2、调用store 的方法更新状态
    // this.props.store.dispatch(actions.decrement(number))
    this.props.decrement(number)
  }
  incrementIfOdd = () => {
    //1、得到选择增加数量
    const number = this.select.value * 1
    //2、得到原本的count 状态
    // const count = this.state.count
    // const count = this.props.store.getState()
    const count = this.props.count
    //3、判断 满足条件才更新状态
    if (count % 2 == 1) {
      // this.setState({ count: count + number })
      // this.props.store.dispatch(actions.increment(number))
      this.props.increment(number)
    }
  }
  incrementAsync = () => {
    //1、得到选择增加数量
    const number = this.select.value * 1
    //2、得到原本的count 状态 并计算新的count
    // const count = this.state.count
    //3、启动延时定时器 更新状态
    setTimeout(() => {
      // this.setState({ count: count + number })
      // this.props.store.dispatch(actions.increment(number))
      this.props.increment(number)
    }, 1000)
  }
  render() {
    const { count } = this.props
    // const count = this.props.store.getState()
    return (
      <div className="App">
        <p>click {count} times</p>
        <div>
          <select ref={(select) => (this.select = select)}>
            <option value="1">1</option>
            <option value="2">2</option>
            <option value="3">3</option>
          </select>
          &nbsp;&nbsp;
          <button onClick={this.increment}>+</button>&nbsp;&nbsp;
          <button onClick={this.decrement}>-</button>&nbsp;&nbsp;
          <button onClick={this.incrementIfOdd}>increment if odd</button>
          &nbsp;&nbsp;
          <button onClick={this.incrementAsync}>increment async</button>
        </div>
      </div>
    )
  }
}
// function App() {}

// export default connect((state) => ({ count: state }), { increment, decrement })(
//   App,
// )

容器组件

import React from 'react'
import { connect } from 'react-redux'
import { increment, decrement } from '../redux/actions'

import Counter from '../componments/Counter'

export default connect((state) => ({ count: state }), { increment, decrement })(
  Counter,
)

最后修改index.js 中引入的入口组件即可

redux 异步编程

1、下载redux 插件(异步中间件)

       npm install --save redux-thunk

2、代码中引入

3、将异步的操作放在action中,action 返回的是一个函数,在特定的时间才触发对应的事件

   action 中 代码 定时器模拟异步延时:

export const incrementAsync = (number) => {
    return dispatch => {
        // 1s 之后才去分发一个增加的action
        setTimeout(() => {
            dispatch(increment(number))
        }, 1000)
    }
}

相关重要知识  纯函数& 高阶函数

1、纯函数

1)    一类特别的函数: 只要是同样的输入,必定得到同样的输出
2)    必须遵守以下一些约束  
       a.    不得改写参数
       b.    不能调用系统 I/O 的API
       c.    能调用Date.now()或者Math.random()等不纯的方法  
3)    reducer函数必须是一个纯函数

2、高阶函数

1)    一类特别的函数: 只要是同样的输入,必定得到同样的输出
2)    必须遵守以下一些约束  
       a.    不得改写参数
       b.    不能调用系统 I/O 的API
       c.    能调用Date.now()或者Math.random()等不纯的方法  
3)    reducer函数必须是一个纯函数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值