初学者认识redux

309 阅读5分钟

1、redux使用

  • 了解redux
  1. redux 是一个独立专门用于做状态管理的js库(不是react的插件库)
  2. redux可以在react,angular, vue等项目中使用,但大多数情况下,都是配合react适用
  3. redux是集中管理应用中多个组件共享的状态
  • redux工作流
  1. 首先,用户发出action;
  2. 然后store自动调用reducer,并且传入两个参数,当前State和收到的Action, Reducer会返回新的State;
  3. views会根据store数据的改变执行页面刷新渲染的操作。

image.png

  • 什么情况下使用redux
  1. 某个组件的状态需要共享;
  2. 某个状态需要在任何地方都可以拿到;
  3. 一个组件需要改变全局状态;
  4. 一个组件需要改变另一个组件的状态;
  • redux的api
  1. createStore()
作用:创建包含指定reducer的store对象
编码:
    import {createStore} from 'redux'
    import reducer from './reducer'
    const store = createStore(reducer)
  1. store对象
作用:redux库最核心的管理对象
它内部维护者: state,reducer
核心方法:getState()、dispatch(action)、subscribe(listener)
使用:
    store.getState()
    store.dispatch({type:'INCREMENT',number})
    store.subscribe(render)
  1. applyMiddleware()
作用:基于redux 的中间件(插件库)
编码:
    import {createStore, applyMiddleware} from 'redux'
    import thunk from 'redux-thunk'. //redux异步中间件
    const store = createStore(
        conunter,
        applyMiddleware(thunk) //应用上异步中间件

4.combineReducers()

    作用:合并多个reducer函数
    编码:
        export default combineReducers({
            user,
            tagLister,
            chat,
        })

2、redux的和心概念

  • action
1、标识要执行行为的对象
1、包含两个方面的属性
    a. type: 标识属性,值为字符串,唯一,必要属性
    b. 数据属性,值类型任意,可选属性
3、例子:
    const action = {
        type: 'ADD',
        data: 2
    }
4、action creater(创建Action的工厂函数)
    const increment = (num) => ({type: 'ADD', data: num})
  • reducer
1、根据老的state和action,产生新的state的纯函数
2、样例
    export default function counter(state = 0, action) {
        switch(action.type) {
            case 'ADD':
              return state + action.data;
             default:
              return state;
         }
    }
3、注意:
    a、返回一个新的状态
    b、不要修改原来的状态
  • store
1、将state、action和reducer联系在一起的对象
2、如何得到此对象?
    import {createStore} from 'redux'
    import reducer from './reducer'
    const store = createStore(reducer)
3、此对象的功能
    getState() 得到state
    dispatch(action): 分发action,触发reducer调用,产生新的state
     subscribe(listener): 注册监听,当产生了新的state时,自动调用

3、redux使用例子

1、新建文件夹:redux

2、新建redux/action-type.js

/* action对象的type常量名称模块  */
export const ADD = 'add'
export const REMOVE = 'remove'

3、新建redux/action.js

/* action creater 模块
   包含n个action creator函数
   */
   
import {ADD, REMOVE} from './action-type.js'
imoirt const add = (num) => ({type: ADD, num})
import const remove = (num) => ({type: REMOVE, num})

4、新建redux/reducer.js

import {ADD, REMOVE} from './action-type.js'

export default function count(state = 0, action) {
    switch (action.type) {
        case ADD:
            return state + action.num;
        case REMOVE:
            return state - action.num;
        default:
            state;
    }
}

5、新建redux/store.js

/* redux最核心的管理对象store  */

import {createStore} from 'redux';
import reducer from './reducer';

export default createStore(reducer);

6、APP.jsx

import React,{Component} from 'react';
import PropTypes from 'prop-types';
import {add, remove} from './redux/action.js';
// 应用组件
export default class App extends Component {
    static propTypes = {
       store: ProtoTypes.object.isRequired
    }
    
    constructor (props) {
        super(props)
        this.numRef = React.createRef()
    }
    
    add = () => {
        const num = this.numRef.current.value*1
        this.props.store.dispatch(add(num))
    }
    
    remove = () => {
        const num = this.numRef.current.value * 1
        this.props.store.dispatch(remove(num))
    }
    
    render() {
      const count = this.props.store.getState()
      return (
        <div>
           <p>当前值 {count}</p>
           <input ref={this.numRef} value={count}/>
           <button onClick={this.add}>+</button>
           <button onClick={this.remove}>-</button>
        </div>
      )
   }
}

7、index.js

 /* 入口js. */
 import React from 'react'
 import ReactDOM from 'react-dom'
 
 import App from './App'
 import store from './redux/store'
 
 /* 将store 传递给App组件。*/
 ReactDOM.render(
     <APP store={store} />,
     document.getElementById('root')
 )
 
 /* 通过store订阅state改变的监听 =》 一旦store中的state改变了,立即调用回调函数。*/
 store.subscribe(() => {
   React.render(
      <APP store={store} />,
      document.getElementById('root')
   )
 })

4、react-redux

  • react-redux将所有组件分为两类
  1. UI组件
a. 只负责UI的呈现,不带有任何业务逻辑
b. 通过props接收数据
c. 不使用任何redux的API
d. 一般保存在components文件夹下
  1. 容器组件
a. 负责管理数据和业务逻辑,不负责UI的呈现
b. 适用ReduxAPI
c.  一般保存在containers 文件夹下
  • react-redux的api Provider
/* 让所有组件都可以得到state数据  */
<Provider store={store}><App/></Provider>

connect

/* 用于包装UI组件生成容器组件 */
connect(
    mapStateToprops,
    mapDispatchToprops
)(Counter)

mapStateToprops

/* 函数:将state数据转换为UI组件的标签属性 */
function mapStateToProps(state){
    return {
        count: state
    }
}

mapDispatchToprops

/* 将分发action的函数转换为UI组件的标签属性 */
function mapDispatchToProps(dispatch) {
    return {
        add: (num) => dispatch(add(num)),
        remove: (num) => dispatch(remove(num)),
    }
}

//对象: 简洁语法,可以直接指定包含多个action方法
const mapDispatchToProps = {
    add,
    remove,
}
  • react-redux的使用

    1、下载以来包:npm install --save react-redux

    2、redux/action-type.js. 不变

    3、redux/action.js. 不变

    4、redux/reducers.js. 不变

    5、redux/ store.js. 不变

    6、components/Counter.jsx

import React, {Component} from 'react'
import PropTypes from 'prop-types'

/* 应用组件 */
export default class Counter extends Component {
    static propTypes = {
        count: PropTypes.num.isRequired,
        add: PropTypes.func.isRequired,
        remove: PropTypes.func.isRequired,
    }
    
    constructor (props) {
        super(props)
        this.numRef = React.createRef()
    }
    
    add = () => {
        const num = this.numRef.current.value * 1
        this.props.add(num)
    }
    
    remove = () => {
        const num = this.numRef.current.value * 1
        this.props.remove(num)
    }
    
    render() {
        const count = this.props.count
        return (
            <div>
               <p>当前count{count}</p>
               <input ref={this.numRef} value={count}/>
               <button onClick={this.add}>+</button>
               <button onClick={this.remove}>-</button>
            </div>
         )
   }
}

7、containters/App.jsx

/* 包装UI组件的容器组件,通过connec()生成  */
import React from 'react'
import {connect} from 'react-redux'
import Counter from '../components/Counter'
import {add, remove} from '../redux/actions'

/* functionmapStateToProps(state) {
        return {
            count:state
         }
   }
   
functionmapDispatchToProps(dispatch) {
    return {
        add:(num) => dispatch(add(num)),
        remove:(num) => dispatch(remove(num)),
    }
}

const mapDispatchToProps = {add,remove}

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(Counter) */

export default connect(
    state => (count: state}),
    {add, remove}
)(Counter)

8、index.js

/* 入口js */
import React from 'react'
import ReactDOM from 'react-dom'
import {Provider} from 'react-redux'
import App from './containers/App'
import store from './redux/store'  //引入store

//将store 传递给Provider组件
ReactDOM.render((
    <Provider store={store}>
        <App />
    <Provider>
), document.getElementById('root'))
  • redux异步编程 1、下载redux-thunk插件npm install --save redux-thunk 2、redux/store.js
/* redux最核心的管理对象store */
 import {createStore, applyMiddleware} from 'redux'
 import thunk from 'redux-thunk'
 import reducer from './reducer'
 
 export default createStore(reducer, applyMiddleware(thunk))

3、redux/action.js

/* 增加异步的action */
export const addAsync = function(num) {
    // 返回一个带dispatch参数的函数
    return dispatch => {
        setTimeout(() => {
            dispatch(add(num))
        }, 1000)
    }
}
        

4、redux/Counter.jsx

/* */
static propTypes = {
    count: PropTypes.num.isRequired,
    add: PropTypes.func.isRequired,
    remove: PropTypes.func.isRequired,
    addAsync: PropTypes.func.isRequired,
}
 addAsync = () => {
     const num = this.numRef.current.value * 1
     this.props.addAsync(num)
 }

5、containers/App.jsx

import {addAsync} from '../redux/actions'
/* 向外暴露连接App组件的包装组件 */
export default connect(
    state => ({count: state}),
    {addAsync}
 )(Counter)