react-redux详细使用方法@郝晨光

前言

这篇文章是之前我发表在CSDN上边的,最近搬到简书

文件目录

    *---store   // 存放redux,数据,以及action
    
    *---store子目录
        actions  // 存放action的文件夹
        reducers // 存放reducer的文件夹
        actionTypes.js // 存放所有的actionType
        index.js // store的入口文件

安装

   npm install redux react-redux -S
   cnpm install redux react-redux -S
   yarn add redux react-redux -S

使用

  • 先在index.js中引入react-redux定义的Provider组件,并包裹在App组件外部
 import React from 'react';
 import ReactDOM from 'react-dom';
 import { Provider } from 'react-redux';
 import App from './App';
 
 ReactDOM.render(
     <Provider>
         <App />
     </Provider>,
     document.getElementById('root')
 );
  • 接着在store目录下的index.js中创建一个store,并抛出
 import { createStore, combineReducers } from 'redux';
  // createStore方法是用来创建store的,combineReducers方法是用来合并多个reducer的
  
  // 创建根reducer,利用combineReducers合并多个reducer,此处还未定义reducer,所以暂空
  const rootReducer = combineReducers({
  
  })
  
  // 创建初始化的state,初始化为一个空对象即可,默认的数据建议都写在reducer上
  const initializeState = {}; // 定义初始化的state
  
  // 创建store,第一个参数是根reducer,第二个参数可以是初始化的state,也可以是别的,暂且不提
  const store = createStore(rootReducer,initializeState);
  
  // 抛出store
  export default store;  
  • 在src/index.js中引入store,并且在Provider组件上使用
  /**之前的代码**/
 import store from './store';
  
 ReactDOM.render(
    <Provider store={store}>
        <App />
    </Provider>,
    document.getElementById('root')
 );
  • 接着可以先定义数据,即定义reducer,在src/store/reducers目录下,新建reducer,例如countReducer.js
  // 定义初始化的数据,根据实际数据即可
  const initializeState = {
      count: 1
  }
        
 // 定义reducer,第一个参数为state,赋予默认值为上边定义的initializeState,
// 第二个参数为action,并return一个state  
 // 并且抛出这个countReducer
 export default function countReducer(state = initializeState,action) {
      return state;
 }
  • 在src/store/index.js中引入定义的countReducer,并合并到rootReducer中
 // 引入countReducer, 
 import countReducer from './reducers/countReducer';
       
 // 将countReducer合并到rootReducer上,并使用原有名称
 const rootReducer = combineReducers({
      countReducer
 })
       
 // 也可以给countReducer改名,如下,改名成为count
 const rootReducer = combineReducers({
         count: countReducer
 })
  • 接着只需要将组件改造一下,就可以使用reducer上边的数据了

  • 在src/APP.js中,或者是你需要使用store中数据的组件中,引入react-redux提供的connect方法

 import { connect } from 'react-redux';
  • 并且在抛出之前,定义获取数据的方法mapStateToProps

      // 定义方法mapStateToProps,参数为state,并且返回一个对象,对象内定义需要获取的store内的数据,
      // 由于是使用的countReducer中的数据,所以需要使用state.countReducer.属性名 
      function mapStateToProps(state) {
           return {
               count: state.countReducer.count
           } 
      }
    
  • 接着,在抛出的时候调用connect方法改造当前组件

// connect的第一个参数为数据,即mapStateToProps方法
// 接着在第二个括号内传入当前需要被改造的组件  
export default connect(mapStateToProps)(App);
  • 然后,我们在被改造的组件内就可以通过this.props.属性名获取store中的数据了,例如我在mapStateToProps方法中返回的是count数据,所以我在App组件中使用this.props.count即可
class App extends Component {
   render() {
       return (
           <div>
               {this.props.count}
           </div>
       );
    } 
}
  • 获取到数据之后,接着应该是修改仓库内的数据

  • 修改数据首先需要定义一个dispatch,在redux中,修改数据必须通过dispatch提交一个action来进行,在src/store/actions目录下新建countAction.js

  • 在countAction.js中定义addCount方法,并return一个对象,对象上有一个type属性,这个属性对应的是一个常量字符串,这个字符串定义在src/store/actionTypes.js中,主要是为了可以公共的管理,因为同一个常量需要在两个地方使用

 // countAction.js
 
 import { ADD_COUNT } from '../actionTypes'
 
 export function addCount() {
     return {
         type: ADD_COUNT
     }
 }
 
 // actionTypes.js
 
 export const ADD_COUNT = 'ADD_COUNT';
  • 接着在src/store/reducers/countReducer.js中,引入ADD_COUNT常量,并使用switch语句,或者if语句对action.type进行判断,当触发这个action的时候,让当前这个reducer的state.count加一

        import { ADD_COUNT } from '../actionTypes';
    
        export default function countReducer(state = initializeState,action) {
            switch (action.type) {
                case ADD_COUNT:
                    return { count: state.count + 1 };
                default:
                    return state;
            }
        }   
    
  • 紧接着,要在组件中使用这个addCount方法,提交这个dispatch,触发这个action

  • 在App.js或者是使用store的组件中,首先引入addCount方法,然后在mapStateToProps的下边,在定义一个mapActionToProps方法,接着在connect的第二个参数位置,传入这个方法即可

  • 在mapActionToProps方法中,第一个参数为dispatch,return一个对象,对象上定义方法
    方法名自定义即可,接着触发这个方法的时候,触发dispatch(),并传入引入的addCount()方法,需要加括号调用,因为只有调用才会返回一个对象,( 或者addCount直接是一个对象,而不是一个函数 )

      import { addCount } from './store/actions/countAction'
      
      /** 其余代码 **/
      
      /** mapStateToProps **/
      
      function mapActionToProps(dispatch) {
          return {
              addCount: () => dispatch(addCount())
          }
      }
      
      export default connect(mapStateToProps,mapActionToProps)(App);
    
  • 此时,可以在App组件内调用this.props.addCount()方法来修改store中的数据了

  • 当然,但凡是方法,都可以传参,

  • 首先在src/store/actions/countAction.js中定义一个新的方法,

  • 当然,这个方法用到的REDUCE_COUNT常量要定义在src/store/actionTypes.js中

      // src/store/actions/countAction.js
      export function reduceCount(num) {
          return {
              type: REDUCE_COUNT,
              num
          }
      }
    
      // src/store/actionTypes.js
      export const REDUCE_COUNT = 'REDUCE_COUNT';
    
  • 而且,在src/store/reducers/countReducer.js中,需要通过switch进行判断action,并执行操作

  • 由于我们在action中定义的对象的属性是num,所以在reducer中进行参数使用的时候,也是使用action.num

  // src/store/reducers/countReducer.js
  import { ADD_COUNT, REDUCE_COUNT } from '../actionTypes'
  
  export default function countReducer(state = initializeState,action) {
      switch (action.type) {
          case ADD_COUNT:
              return { count: state.count + 1 };
          // 新增   
          case REDUCE_COUNT:
              return { count: state.count - action.num };
          default:
              return state;
      }
  }
  • 在App.js中使用reduceCount方法
 import { addCount, reduceCount } from './store/actions/countAction';

 /** 其余代码 **/
 
 /** mapStateToProps **/
 
 function mapActionToProps(dispatch) {
     return {
         addCount: () => dispatch(addCount()),
         reduceCount: (num) => dispatch(reduceCount(num))
     }
 }
  • 接着在组件中直接调用this.props.reduceCount()方法,并传入一个参数即可

  • 最后,为了遵循react的规范,我们需要在给组件定义props的时候,规定props的类型

  • 首先在App.js或者使用store的组件中,引入prop-types

  • 然后在文件最末尾,抛出之前,定义所有的props的类型

import PropTypes from 'prop-types';
 /** 其余代码 **/
       
App.propTypes = {
   count: PropTypes.number.isRequired,
   addCount: PropTypes.func.isRequired,
    reduceCount: PropTypes.func.isRequired
}

最终代码

index.js

 import React from 'react';
 import ReactDOM from 'react-dom';
 import { Provider } from 'react-redux';
 import store from './store';
 import App from './App';
 
 ReactDOM.render(
     <Provider store={store}>
         <App />
     </Provider>,
     document.getElementById('root')
 );

App.js

 import React, {Component} from 'react';
 import { connect } from 'react-redux';
 import { addCount, reduceCount } from './store/actions/countAction';
 import PropTypes from 'prop-types';
 
 class App extends Component {
     render() {
         return (
             <div>
                 <button onClick={()=>this.props.addCount()}>加1</button>
                 {this.props.count}
                 <button onClick={()=>this.props.reduceCount(5)}>减5</button>
             </div>
         );
     }
 }
 
 function mapStateToProps(state) {
     return {
         count: state.countReducer.count
     }
 }
 
 function mapActionToProps(dispatch) {
     return {
         addCount: () => dispatch(addCount()),
         reduceCount: (num) => dispatch(reduceCount(num))
     }
 }
 
 App.propTypes = {
     count: PropTypes.number.isRequired,
     addCount: PropTypes.func.isRequired,
     reduceCount: PropTypes.func.isRequired
 }
 
 export default connect(mapStateToProps,mapActionToProps)(App);

store/index.js

 import { createStore, combineReducers } from 'redux';
 import countReducer from './reducers/countReducer';
 
 const rootReducer = combineReducers({
     countReducer
 })
 
 const initializeState = {}; // 定义初始化的state
 
 const store = createStore(rootReducer,initializeState);
 
 export default store;

store/actionTypes.js

 export const ADD_COUNT = 'ADD_COUNT';
 export const REDUCE_COUNT = 'REDUCE_COUNT';

store/reducers/countReducer.js

 import { ADD_COUNT, REDUCE_COUNT } from '../actionTypes'
 
 const initializeState = {
     count: 1
 }
 
 export default function countReducer(state = initializeState,action) {
     switch (action.type) {
         case ADD_COUNT:
             return { count: state.count + 1 };
         case REDUCE_COUNT:
             return { count: state.count - action.num };
         default:
             return state;
     }
 }

store/actions/countAction.js

 import { ADD_COUNT, REDUCE_COUNT } from '../actionTypes'
 
 export function addCount() {
     return {
         type: ADD_COUNT
     }
 }
 
 export function reduceCount(num) {
     return {
         type: REDUCE_COUNT,
         num
     }
 }

- 如果需要使用中间件的话

  • 在store/index.js中,引入applyMiddleware,并使用在createStore的第三个参数位置
  • 接着引入需要使用的中间件,比如redux-thunk
  • 定义一个数组,用来存放所有的中间件
  • 在applyMiddleware方法中展开该数组即可
 import { createStore, combineReducers, applyMiddleware } from 'redux';
 // 引入redux-thunk
 import thunk from 'redux-thunk';

 // 定义中间件的数组
 const middleware = [ thunk ]

 // 使用
 const store = createStore(rootReducer,initializeState,applyMiddleware(...middleware));



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

推荐阅读更多精彩内容