redux和react-redux的使用詳解

我本身的理解redux就跟vue中的vuex差很少,都是數據管理器,話很少說,咱們從經典的計數器案例開始講解vue

使用redux實現計數器react

建立以下的react項目,我習慣把每個模塊分塊,纔有這麼多文件,固然你也能夠寫在一個js文件中,這不是重點vuex

首先咱們看一下項目的入口文件index.js編程

import 'core-js/fn/object/assign';
import React from 'react';
import ReactDOM from 'react-dom';
import Counter from './components/Counter'; //引入計數器件
import {createStore} from 'redux'; //經過解構賦值獲得createStore,爲store的建立作準備
import reducer from './reducers/index' //引入reducer純函數 該函數,根據action的type不一樣結合舊的state返回新的state
let store = createStore(reducer); //建立redux的核心 store store我會在後面進行詳細的解答
import {numAdd,numDel} from './actions/index'; //引入action函數,觸發什麼操做,就根據操做怎樣改變值

// Render the main component into the dom
//這裏使用Redducer變量來定義ReactDOM中的render函數,是方便store中state更新以後,頁面的渲染
const Redducer = () =>{
  ReactDOM.render(
    <Counter     
      value={store.getState()} 
      add ={()=>store.dispatch(numAdd())}
      del ={()=>store.dispatch(numDel())}
    ></Counter>,
    document.getElementById('app')
  );
};
// value={store.getState()} 給展現組件Counter傳遞數據 這裏的store.getState()獲得的值,就是store建立過程當中reducer純函數裏面的初始state值
// ()=>store.dispatch(numAdd())和()=>store.dispatch(numDel()) 定義函數傳遞給展現組件Counter
//store.dispatch(參數)會傳遞一個對象做爲參數例如{type:"add"},調用reducer純函數,實現store中的state的更新

Redducer();//該函數執行,就初始化了頁面

store.subscribe(Redducer);
//store.subscribe()用來監聽store中大的state是否發生改變,若是發生改變,就從新渲染頁面,因此纔跟Redducer()進行綁定

在看純函數reducer,至於爲何redux負責state編輯的函數統稱reducer,我本身的猜想是根據es5中的reduce方法有關(純屬瞎猜想,切勿當真)redux

const reducer = (state=0,action)=>{
  switch (action.type){
    case 'add':
      return state+1;
    case 'del':
      return state-1;
    default:
      return state
  }
};
//定義store的state = 0,action接受的值就是store.dispatch(numAdd())中經過numAdd()函數的到的一個對象
//因爲前面在獲得store的時候 該函數跟redux中的createStore進行了綁定 也就是這一句代碼 let store = createStore(reducer)
//因此經過這裏就能夠改變store的state值,因此說如今能夠的理解reducer爲何是一個純函數了吧
export default reducer;

在看actions中的導出函數app

export const numAdd = ()=>{
  return{
    type:"add"
  }
};
export const numDel = ()=>{
  return{
    type:"del"
  }

}
//導出兩個函數,每個函數返回一個包含type屬性的對象(注意ation中type是必須的,其餘的屬性能夠自行添加),能夠經過解構賦值獲得每個
//的函數,就像入口文件index.js中的這一句代碼 import {numAdd,numDel} from './actions/index';

最後看展現組件Counterdom

import React from 'react';
//函數返回組件的話,就是解構賦值獲取數據
// const Counter = ({ value, add, del })=>{
//   return(
//    <div>
//      <p style={{color:'red'}}>
//        點擊次數{value}
//      </p>
//      <button onClick={add}>加一</button>
//      <button onClick={del}>減一</button>
//    </div>
//   )
// };


//class返回組件的話,就是直接獲取當前組件自身的屬性,就能夠獲取到本身想要的數據
class Counter extends React.Component {
  render() {
    return (
      <div>
        <p style={{color: 'red'}}>
          點擊次數{this.props.value}
        </p>
        <button onClick={this.props.add}>加一</button>
        <button onClick={this.props.del}>減一</button>
      </div>
    )

  }
}
export default Counter;

在這裏我使用了兩種方式來建立組件,第一種經過函數的方式建立的組件,要獲取在入口文件index.js中傳過來的數據,只能經過形參解構賦值的到數據,第二種經過class建立的組件只能經過組件自身的屬性,來獲取數據,固然也能夠經過解構賦值來獲得本身想要的數據,代碼以下異步

class Counter extends React.Component {
  render() {
    let {value,add,del} = this.props;
    return (
      <div>
        <p style={{color: 'red'}}>
          點擊次數{value}
        </p>
        <button onClick={add}>加一</button>
        <button onClick={del}>減一</button>
      </div>
    )

  }

 

綜上全部的代碼就能夠實現了簡單的計數器的功能,這就是redux最基本的使用方法,提示:redux和reat-redux須要本身安裝,最好使用--save來安裝ide

 

接下來就是使用redux和react-redux來實現計數器異步編程

且看代碼

import React, { Component } from 'react' //引入react
import PropTypes from 'prop-types' //引入限制UI組件(展現組件)屬性限制
import ReactDOM from 'react-dom' //引入react-dom相關的對象
import { createStore } from 'redux' //引入redux
import { Provider, connect } from 'react-redux'//引入react配套的redux

// 建立react組件(或者是虛擬節點)
class Counter extends Component {
  render() {
    const { value, onIncreaseClick } = this.props;
    //經過解構賦值獲得相應的屬性裏面的值
    //在這裏Counter是UI組件(展現組件)其屬性是其外面的容器組件中的state是經過react-redux中的connect操做以後傳遞過來的
    return (
      <div>
        <span>{value}</span>
        <button onClick={onIncreaseClick}>Increase</button>
        {/*經過點擊事件觸發綁定的屬性,很明顯,在這裏onIncreaseClick是一個方法或者是一個對象的key值,其映射的value值是一個函數*/}
      </div>
    )
  }
}

//對展現組件中屬性各個值得類型進行限制 不合符規則會報錯
Counter.propTypes = {
  value: PropTypes.number.isRequired, //屬性對象中的value必須是number類型還有必須有值
  onIncreaseClick: PropTypes.func.isRequired //屬性對象中的onIncreaseClick必須是函數還有必須有值
};

// 這裏定義的是一個action對象,個人理解就是跟vuex中actions的做用差很少,發送不一樣的動做名稱,經過配套其餘函數的監聽
//實現容器組件的狀態(state)的改變,只不過vuex中的actions是發送動做名,redux是根據actions對象中的type的值不一樣,進行不一樣的操做

const increaseAction = { type: 'increase' };

// 定義reducer純函數,reducer函數的做用就是,根據傳過來的action和舊state的狀態值
//而後根據action的type的值進行不一樣的操做,進行新的state的返回,從而達到UI組件(展現組件)的從新渲染
function counter(state = { count: 0 }, action) {
  const count = state.count;
  switch (action.type) {
    case 'increase':
      return { count: count + 1 };
    default:
      return state
  }
}

// 建立store對象,能夠說store是redux的核心,由於根據redux的設計理念,
//對state的操做都是根據store中的各類方法實現的,便於管理
//在這裏規定使用redux中的createStore和reducer純函數結合來獲得咱們想要的store
const store = createStore(counter);

//mapStateToProps是connect的第一個參數
//根據名稱咱們知道是把以前reducer純函數中的state(狀態)和展現組件的props(屬性)進行映射
function mapStateToProps(state) {
  return {
    value: state.count
  }
}

// mapDispatchToProps是connect的第二個參數
//根據名稱咱們能夠知道是把reducer純函數中以前store中的dispatch方法和展現組件的props(屬性)進行映射
function mapDispatchToProps(dispatch) {
  return {
    onIncreaseClick: () => dispatch(increaseAction)
  }
}

// 這裏定義App爲react-redux設計理念中的容器組件
//經過connect中傳遞參數和展現組件Counter相結合得出相應的容器組件App
//這裏的容器組件App裏面包含了展現組件Counter
const App = connect(
  mapStateToProps,
  mapDispatchToProps
)(Counter);

//向目標元素渲染容器組件App
//這裏的組件Provider是一個react-redux中特殊的組件
//注意: 1. Provider中有且只有一個子組件(這裏就是App容器組件,不必定是容器組件,根據本身的業務需求本身操做)
//      2. 使用Provider組件的好處是,只須要給Provider組件設置屬性,那麼其子組件和其子組件中的子組件均可以直接使用其對應的屬性
//      3. 避免了組件嵌套以後一個一個傳遞的複雜操做
ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('app')
)

在這裏就完成了redux和react-redux的結合使用,經過本身的學習,我發現了編程思想是多麼的重要,我感嘆於react-redux這種思想的深度,總體感受乾淨,使得展現組件和容組件既相互分離又有必定的結合,兼職就是藕斷絲連,可是又不會違背組件分離的思想,簡直就是強大

,好了基礎的redux和react-redux的講解就到此結束了,後面我還會寫出redux異步編程的理解,畢竟如今的都是同步實現

相關文章
相關標籤/搜索