Redux初析

一.前言

你可能不需要Redux,那就别瞎搞!!!
Redux 的适用场景:多交互、多数据源。

二.简介

三个点:action,view,state。

在Redux中 一个 State 对应一个 View。只要 State 相同,View 就相同。而且State 是View导致的。

简单的来说就是用户接触不到State ,只能在View的层面,操作View通过Action发出通知,从而改变State。

当Store 收到 Action 以后,会返回一个新的 State,来改变View。这个过程就叫做 Reducer,且它是一个函数,是一个纯函数

重要:Action只是通知我要改变了,而Reducer才是告诉你怎么去改变,告诉你怎么做才符合社会主义核心价值观,告诉你怎么才无愧于一个当代青年人。

Redux中的state是Redux自己的数据,React通过store.getState来获取,store.dispatch来修改

三.combineReducers

由于整个应用只有一个 State 对象,包含所有数据,对于大型应用来说,这个 State 必然十分庞大,导致 Reducer 函数也十分庞大

  • 拆分reducer
    将不同的action交给不同的函数来计算,最后合成一个reducer

    import { combineReducers } from 'redux';
    
    let defaultState = {
          count:0,
          otherdata:0
    }
    
    const count = (count = defaultState.count,action) => {
         switch (action.type) {
         case 'increase':
            return count + 1 ;
         default:
            return count
       }
    }
    
    const otherdata = (otherdata = defaultState.otherdata,action) => {
        switch (action.type) {
        case 'reduce':
            return otherdata - 1 ;
       default:
           return otherdata
       }
    }
    
    export default combineReducers({
        count,
        otherdata
    });
    

四.MiddleWare

实际项目中涉及到很多异步操作,那么在Redux要实现异步,得依靠中间键,中间键如果是非必须的话尽量使用现成的中间键。自己造轮子。。。。。。。。。。你懂得~

一般我们要想添加其他功能选择是在发送Action的时候添加,那就是我们的store.dispatch方法上做文章。
但是store.dispatch作为Action的载体只能接受一个对象,我们添加不了其他功能。

这里就需要用到redux-thunk中间键。

使用方法:命令行在目录下执行:cnpm install --save redux-thunk

  import thunk from 'redux-thunk';

使用过后store.dispatch这个方法可以接受一个函数作为参数,ok,可以搞事了!
废话不多说
实践才是检验真理的唯一标准。

这里只是很简略的介绍了Redux,基本的使用方法请参照Redux中文网

五.React-Redux

  • 为什么要使用React-Redux
    • redux为我们解决了什么?
      使用了redux我们在数据传递从下到上的传递不需要一层一层的上报,redux就相当于一个战略指挥中心,你只需要告诉redux,然后让redux去重新计划(渲染)
    • redux渲染
      首先我们得调用store.getState()方法获取到改变后的state,然后再赋值到this.props属性上,然而这只得到了数据。我们知道react的重新渲染需要调用setState方法,而redux则提供了store.subscribe(render)方法,一旦state改变即调用render方法重新渲染
    • redux没有解决的问题
      使用了redux解决了向上传递的问题,但是向下的传递依然是一层一层的,无法直接通知到某个子组件,解决的方案也有,就是:
      • 在父组件利用store.getState()获取值
      • 在通过原生react的方式一层层往下传递
        而react-redux恰好解决了这个问题。
  • React-Redux解决数据下发的问题
    • 组件通过在connect时的mapStateToProps函数中映射state值即可直接通过this.props.xxx获取到值
    • 组件通过在connect时的mapStateToProps函数中映射相同的state,即可实现不同组件数据共享

在React-Redux中所有组件分为UI组件(presentational component)和容器组件(container component)两大类
UI 组件负责 UI 的呈现,容器组件负责管理数据和逻辑

另外React-Redux 提供connect方法,用于从 UI 组件生成容器组件

connect方法有两个参数mapStateToProps和mapDispatchToProps

mapStateToProps:映射Redux state到组件的属性

  • mapStateToProps会订阅 Store,每当state更新的时候,就会自动执行,重新计算 UI 组件的参数,从而触发 UI 组件的重新渲

mapDispatchToProps:映射Redux actions到组件的属性

  • mapDispatchToProps用来建立 UI 组件的参数到store.dispatch方法的映射
  • 它可以是一个函数,也可以是一个对象。如果mapDispatchToProps是一个函数,会得到dispatch和ownProps(容器组件的props对象)
  • 定义了 UI 组件的参数怎样发出 Action

需要获取store值的组件或者发送action的组件都需要connect

当容器组件生成过后React-Redux提供了<Provider>组件,让容器组件拿到state。然后在将根组件包起来,这样所有的根组件就能够拿到state了。
像这样:

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

注意:这里App并不能直接获得store中的数据,必须通过connect生成ui组件,才能通过this.props.xxx获取。

那么子组件之间的共享就必须在两个组件connect时的mapStateToProps函数中映射同样的state

简单说一下bindActionCreators

bindActionCreators是redux官方提供的自动合并action并发送dispatch的方法

code:

  import * as actions from './actions.js'; 
  function mapDispatchToProps(dispatch){  
    return {
      actions:bindActionCreators(actions,dispatch)
    }  
  }  

这样的做法便捷,但是带来的问题是action合并过后,某个组件要发送action时,那么actions就必须要一层一层的往下传,所以不建议使用

五.Do it

使用webpack来构建

package.json

 {
    "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack --mode production",
    "dev": "webpack --watch --mode development"
    },
    "devDependencies": {
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.2",
    "babel-preset-env": "^1.7.0",
    "babel-preset-react": "^6.24.1",
    "css-loader": "^1.0.0",
    "style-loader": "^0.21.0",
    "url-loader": "^1.0.1",
    "webpack": "^4.15.1",
    "webpack-cli": "^3.0.8"
    },
    "dependencies": {
    "react": "^16.8.3",
    "react-dom": "^16.8.3",
    "react-redux": "^6.0.1",
    "redux": "^4.0.1",
    "redux-thunk": "^2.3.0"
    }
}

项目目录:

1.png

这里建议将action和reducer分离开来,因为项目较大的话,你可能会有很多种不同的action或者reducer,方便后期维护。

main.js

import React, { Component } from 'react';  

import ReactDOM from 'react-dom';  

import { createStore , applyMiddleware} from 'redux';  

import { Provider, connect } from 'react-redux';

import thunk from 'redux-thunk';

import * as actions from './actions.js'; 

import reducer from './reducer.js'; 

import Top from './common/Top.js';

import Content from './common/Content.js' 

require('./main.css');

class App extends Component{  
    render() {  
        const {onGetDataClick,list} = this.props;
        let name = "XXX系统";  
        return (  
            <div>  
                <Top name={name} />
                <button onClick={onGetDataClick}>Get</button>
                <Content data={list} />
            </div>  
        );  
    }  
}  

let store = createStore(reducer,applyMiddleware(thunk));        //使用中间键

function mapStateToProps(state) {          //将Redux state映射到组件的属性
    return { 
             list : state.list
           }  
}  

function mapDispatchToProps(dispatch){         //定义事件的action
    return{  
        onGetDataClick:()=>dispatch(actions.getDataAction),  
    }  
}  

App = connect(mapStateToProps, mapDispatchToProps)(App)   //绑定到App组件

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

actions.js

const getDataAction = (dispatch) => {  
    $.ajax({
        url:"xxxxxxxxxxxxxxxxxxxxxxxx",
        type:"post",
        dataType:"json",
        data:{},
        success:function(res){
                   dispatch({type:"RES_SUCCESS",data:data})
        },
        error:function(){
                  dispatch({type:"RES_ERROR"})
        },
        compelet:function(){
                  dispatch({type:"RES_COMPELET"})
       }
    })
}  
export {getDataAction}

这里我们dispatch第一次执行咱们的请求,根据不同状态再发送Action来触发 Reducer

reducer.js

const initialState = {  
    list:[] 
} 

export default (state = initialState, action) => {  
    switch (action.type) {  
        case 'RES_ERROR':  
            return {  
                 list:"Error"
            }  
        case 'RES_COMPELET':  
            return {  
                 list:"Compelet"
            } 
        case 'RES_SUCCESS':
            return {
                list:action.data
            } 
        default:  
            return initialState;  
    }  
}

Reduce中我们接收到一个Action,然后返回一个State,然后映射到组件的属性上,实现View的更新

Content.js

import React, {Component} from 'react';

export default class extends Component{
render() {
    return (
      <div className="content">
          <table id="managelist">
            <thead>
              <tr> //此处不可省略tr,不然react会抛出警告
                  <th>XXX</th>
                  <th>XXX</th>
                  <th>XXX</th>
              </tr>
            </thead>
            <tbody>
                {this.props.data.map(function(item,index){
                 return (
                        ...............................
                )})}
            </tbody>
          </table> 
      </div>
    );
  }
}

粗略介绍,前路漫漫。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,978评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,954评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,623评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,324评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,390评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,741评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,892评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,655评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,104评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,451评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,569评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,254评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,834评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,725评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,950评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,260评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,446评论 2 348

推荐阅读更多精彩内容