Redux and React-redux 莞式教程(新手必看)

爲了方便使用者使用,這裏就redux和react-redux 一併講究使用了,會了react-redux,redux也就沒問題了,只不過稍微封裝了一下前端

教程方式

  1. 咱們先講理論,先明白 render、action、 store 、connect 、 dispatch 、{ mapStateToProps mapDispatchToProps },是什麼東西。node

  2. 看完你可能有點懵,不要緊我有個簡單直接的漲工資的dom,跟着作一遍你就懂了react

先 download 莞式教程 github.com/Chad97/My-n… —— 看了它你就一目瞭然了git

1、

  • 介紹 (有必定了解的本身跳 開始個人莞式教程)

對於大型的複雜應用來講,這兩方面偏偏是最關鍵的。所以,只用 React 無法寫大型應用。 爲了解決這個問題,2014年 Facebook 提出了 Flux 架構的概念,引起了不少的實現。2015年,Redux 出現,將 Flux 與函數式編程結合一塊兒,很短期內就成爲了最熱門的前端架構。es6

首先明確一點,Redux 是一個有用的架構,但不是非用不可。事實上,大多數狀況,你能夠不用它,只用 React 就夠了。 曾經有人說過這樣一句話。 "若是你不知道是否須要 Redux,那就是不須要它。" —— Redux 的創造者 Dan Abramovgithub

簡單說,若是你的UI層很是簡單,沒有不少互動,Redux 就是沒必要要的,用了反而增長複雜性。 用戶的使用方式很是簡單 用戶之間沒有協做 不須要與服務器大量交互,也沒有使用 WebSocket 視圖層(View)只從單一來源獲取數據編程

Store

Store 就是保存數據的地方,你能夠把它當作一個容器。整個應用只能有一個 Store。 Redux 提供createStore這個函數,用來生成 Store。redux

import { createStore } from 'redux';
const store = createStore(fn);
複製代碼

Action

State 的變化,會致使 View 的變化。可是,用戶接觸不到 State,只能接觸到 View。因此,State 的變化必須是 View 致使的。Action 就是 View 發出的通知,表示 State 應該要發生變化了。數組

Action 是一個對象。其中的type屬性是必須的,表示 Action 的名稱。其餘屬性能夠自由設置,社區有一個規範能夠參考。服務器

const action = {
  type: 'ADD_TODO',
  payload: 'Learn Redux'
};
複製代碼

上面代碼中,Action 的名稱是ADD_TODO,它攜帶的信息是字符串Learn Redux。 能夠這樣理解,Action 描述當前發生的事情。改變 State 的惟一辦法,就是使用 Action。它會運送數據到 Store。

Action Creator

View 要發送多少種消息,就會有多少種 Action。若是都手寫,會很麻煩。能夠定義一個函數來生成 Action,這個函數就叫 Action Creator。

const ADD_TODO = '添加 TODO';

function addTodo(text) {
  return {
    type: ADD_TODO,
    text
  }
}
複製代碼

const action = addTodo('Learn Redux'); 上面代碼中,addTodo函數就是一個 Action Creator。

store.dispatch()

store.dispatch()是 View 發出 Action 的惟一方法。

import { createStore } from 'redux';
const store = createStore(fn);

store.dispatch({
  type: 'ADD_TODO',
  payload: 'Learn Redux'
});
複製代碼

上面代碼中,store.dispatch接受一個 Action 對象做爲參數,將它發送出去。 結合 Action Creator,這段代碼能夠改寫以下。

store.dispatch(addTodo('Learn Redux'));

Reducer

Store 收到 Action 之後,必須給出一個新的 State,這樣 View 纔會發生變化。這種 State 的計算過程就叫作 Reducer。

Reducer 是一個函數,它接受 Action 和當前 State 做爲參數,返回一個新的 State。

const reducer = function (state, action) {
  // ...
  return new_state;
};
複製代碼

整個應用的初始狀態,能夠做爲 State 的默認值。下面是一個實際的例子。

const defaultState = 0;
const reducer = (state = defaultState, action) => {
  switch (action.type) {
    case 'ADD':
      return state + action.payload;
    default: 
      return state;
  }
};

const state = reducer(1, {
  type: 'ADD',
  payload: 2
});
複製代碼

上面代碼中,reducer函數收到名爲ADD的 Action 之後,就返回一個新的 State,做爲加法的計算結果。其餘運算的邏輯(好比減法),也能夠根據 Action 的不一樣來實現。

實際應用中,Reducer 函數不用像上面這樣手動調用,store.dispatch方法會觸發 Reducer 的自動執行。爲此,Store 須要知道 Reducer 函數,作法就是在生成 Store 的時候,將 Reducer 傳入createStore方法。

import { createStore } from 'redux';
const store = createStore(reducer);
複製代碼

上面代碼中,createStore接受 Reducer 做爲參數,生成一個新的 Store。之後每當store.dispatch發送過來一個新的 Action,就會自動調用 Reducer,獲得新的 State。

爲何這個函數叫作 Reducer 呢?由於它能夠做爲數組的reduce方法的參數。請看下面的例子,一系列 Action 對象按照順序做爲一個數組。

const actions = [
  { type: 'ADD', payload: 0 },
  { type: 'ADD', payload: 1 },
  { type: 'ADD', payload: 2 }
];
複製代碼

const total = actions.reduce(reducer, 0); // 3 上面代碼中,數組actions表示依次有三個 Action,分別是加0、加1和加2。數組的reduce方法接受 Reducer 函數做爲參數,就能夠直接獲得最終的狀態3。

store.subscribe()

Store 容許使用store.subscribe方法設置監聽函數,一旦 State 發生變化,就自動執行這個函數。

import { createStore } from 'redux';
const store = createStore(reducer);
store.subscribe(listener);
複製代碼

顯然,只要把 View 的更新函數(對於 React 項目,就是組件的render方法或setState方法)放入listen,就會實現 View 的自動渲染。

store.subscribe方法返回一個函數,調用這個函數就能夠解除監聽。

let unsubscribe = store.subscribe(() =>
  console.log(store.getState())
);

unsubscribe();
複製代碼

Store 的實現

上一節介紹了 Redux 涉及的基本概念,能夠發現 Store 提供了三個方法。

store.getState()
store.dispatch()
store.subscribe()
複製代碼

import { createStore } from 'redux'; let { subscribe, dispatch, getState } = createStore(reducer); createStore方法還能夠接受第二個參數,表示 State 的最初狀態。這一般是服務器給出的。

let store = createStore(todoApp, window.STATE_FROM_SERVER) 上面代碼中,window.STATE_FROM_SERVER就是整個應用的狀態初始值。注意,若是提供了這個參數,它會覆蓋 Reducer 函數的默認初始值。

下面是createStore方法的一個簡單實現,能夠了解一下 Store 是怎麼生成的。

const createStore = (reducer) => {
  let state;
  let listeners = [];

  const getState = () => state;

  const dispatch = (action) => {
    state = reducer(state, action);
    listeners.forEach(listener => listener());
  };

  const subscribe = (listener) => {
    listeners.push(listener);
    return () => {
      listeners = listeners.filter(l => l !== listener);
    }
  };

  dispatch({});

  return { getState, dispatch, subscribe };
};
複製代碼

redux flow

  • 放一個簡單的計數器案例
const Counter = ({ value, onIncrement, onDecrement }) => (
  <div> <h1>{value}</h1> <button onClick={onIncrement}>+</button> <button onClick={onDecrement}>-</button> </div>
);

const reducer = (state = 0, action) => {
  switch (action.type) {
    case 'INCREMENT': return state + 1;
    case 'DECREMENT': return state - 1;
    default: return state;
  }
};

const store = createStore(reducer);

const render = () => {
  ReactDOM.render(
    <Counter value={store.getState()} onIncrement={() => store.dispatch({type: 'INCREMENT'})} onDecrement={() => store.dispatch({type: 'DECREMENT'})} />, document.getElementById('root') ); }; render(); store.subscribe(render); 複製代碼

2、

先 download 莞式教程 github.com/Chad97/My-n… —— 看了它你就一目瞭然了

這一章 咱們簡單的講一下 react-redux ,就開始個人莞試教程

咱們的react-redux 爲方便咱們使用,內置了幾個組件,很是簡單,很是好用 —— connect() mapStateToProps mapDispatchToProps <Provider></Provider>

  • 好下面讓咱們來單刀直入~

reacr-redux 之漲工資

npx redux-dom 新建一個react項目 低版本 nodejs 用create-app也能夠

  • src文件夾下面建立一個 store ,store裏面建立一個reducer.js 以下:
import React from 'react';
import { connect } from 'react-redux';


const tiger = 30000//建立工資state

//這是action
const increase = {
    type: '漲工資'
}
const decrease = {
    type: '扣工資'
}

const  taxes = {
    type: '繳稅'
}

//這是reducer
 const reducer = (state = tiger, action) => {
    switch (action.type) {
        case '漲工資':
            return state += 100;
        case '扣工資':
            return state -= 100;
        case '繳稅' :
        return state - ((state - 5000) *  0.01)
        default:
            return state;
    }
}

export default reducer
複製代碼

而後進入咱們的 index.js

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import App from './App'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import reducer from './store/reducer'





//建立store
const store = createStore(reducer);



ReactDOM.render(
    <Provider store={store}> <App /> </Provider>,
    document.getElementById('root')
)
複製代碼
  • 講一下 Provider 這個組件,他是react-redux 中提供的一個組件

connect方法生成容器組件之後,須要讓容器組件拿到state對象,才能生成 UI 組件的參數。 一種解決方法是將state對象做爲參數,傳入容器組件。可是,這樣作比較麻煩,尤爲是容器組件可能在很深的層級,一級級將state傳下去就很麻煩。 React-Redux 提供Provider組件,可讓容器組件拿到state

記住 他就是 經過 class 的connect 實現的,能讓Provider 的組件的子孫組件都拿到掛載的store,莞式教程簡單粗暴,要看實現原理 去看es6去

好了如今讓我去app.js裏面,去實現漲工資吧 哈哈~~~

import React, { Component } from 'react';
import { connect } from 'react-redux';
import Home from './components/Home'

class App extends Component {

  componentDidMount () {
    // console.log(this.props)
  }

  render() {
    const { PayIncrease, PayDecrease } = this.props
    return (

      <div className="App"> <h2>當月工資爲{this.props.tiger}</h2> <button onClick={PayIncrease}>升職加薪</button> <button onClick={PayDecrease}>遲到罰款</button> <Home /> </div>

      

    );
  }
}

//須要渲染什麼數據
function mapStateToProps(state) {
  return {
      tiger: state
  }
}
//須要觸發什麼行爲
function mapDispatchToProps(dispatch) {
  return {
      PayIncrease: () => dispatch({ type: '漲工資' }),
      PayDecrease: () => dispatch({ type: '扣工資' })
  }
}

export default App = connect(mapStateToProps, mapDispatchToProps)(App)

複製代碼
  • connect

React-Redux 提供connect方法,用於從 UI 組件生成容器組件。connect的意思,就是將這兩種組件連起來。

記住,要想讓組件拿到store 就得用 connect () 這個方法 來連接,你能夠理解架橋,別想太多,簡單粗暴 用多了你就知道原理了。

打印工資

好如今讓我在 src/components 羨慕新建一個 Home.jsx 組件 ,漲完工資是否是要打印工資

import React from 'react';
import { connect } from 'react-redux'
import Counter from './Counter '

class Home extends React.Component {
    constructor (props, context){
        super() 
        this.state = {
            
        }
    }
    

    mycl = () => {
        alert(this.props.tiger)
    } 

    render() {
    
        return (
            <div> <hr /> <br /> <h1>home 組件</h1> <button onClick= {this.mycl}>打印目前工資</button> <hr /> <br /> <Counter /> </div>
        );
    }

    componentDidMount () {
        console.log(this.props)
    }

}


//須要渲染什麼數據
function mapStateToProps(state) {
    return {
        tiger: state
    }
  }
  //須要觸發什麼行爲
  function mapDispatchToProps(dispatch) {
    return {
        PayIncrease: () => dispatch({ type: '漲工資' }),
        PayDecrease: () => dispatch({ type: '扣工資' })
    }
  }

export default connect(mapStateToProps, mapDispatchToProps)(Home)
複製代碼

繳稅

漲完工資,工資那麼高是否是要繳稅拉~~

import React from 'react';
import { connect } from 'react-redux';

class Counter extends React.Component {
    constructor(props) {
        super(props);
        this.state = { 

         };
    }
    render() {
        const { Paytaxes } = this.props
        return (
            <div> <h2>稅後計算</h2> <button onClick={ Paytaxes } >繳稅</button> <p>{this.props.tiger}</p> </div>
        );
    }
}

//須要渲染什麼數據
function mapStateToProps(state) {
    return {
        tiger: state
    }
  }
  //須要觸發什麼行爲
  function mapDispatchToProps(dispatch) {
    return {
        PayIncrease: () => dispatch({ type: '漲工資' }),
        PayDecrease: () => dispatch({ type: '扣工資' }),
        Paytaxes: () => dispatch({ type: '繳稅' }),
    }
  }

export default connect(mapStateToProps, mapDispatchToProps)(Counter)
複製代碼

莞式教程,作完就走~~ 手動 /斜眼

相關文章
相關標籤/搜索