react_15Hooks_二(初步了解redux茵瘾,手動實現(xiàn)過程)

上:

JavaScript純函數(shù):
  • 確定的輸入,一定會產(chǎn)生確定的輸出咐鹤;
  • 函數(shù)在執(zhí)行過程中拗秘,不能產(chǎn)生副作用;
    React中要求我們無論是函數(shù)還是class聲明一個組件慷暂,這個組件必須是像純函數(shù)一樣聘殖,保護props不被修改,redux中,reducer要求是一個純函數(shù)行瑞。
    (一):Redux定義:是JavaScript狀態(tài)容器奸腺,提供了可預(yù)測的狀態(tài)管理
核心理念——store

管理數(shù)據(jù)

const initialState = {
  counter: 0
}
核心理念——action

所有數(shù)據(jù)的變化,必須通過派發(fā)(dispatch) action來更新血久;
它是一個普通的js對象突照,用來描述這次更新的type和content;

// actions
const action1 = { type: "INCREMENT" };
const action2 = { type: "DECREMENT" };

const action3 = { type: "ADD_NUMBER", num: 5 };
const action4 = { type: "SUB_NUMBER", num: 12 };
核心理念——reducer

它是一個純函數(shù)氧吐;負責將傳入的state和action結(jié)合起來生成一個新的state讹蘑;

// reducer
function reducer(state = initialState, action) {
  switch (action.type) {
    case "INCREMENT":
      return { ...state, counter: state.counter + 1 }
    case "DECREMENT":
      return { ...state, counter: state.counter - 1 }
    case "ADD_NUMBER":
      return { ...state, counter: state.counter + action.num }
    case "SUB_NUMBER":
      return { ...state, counter: state.counter - action.num }
    default:
      return state;
  }
}

結(jié)合使用:

// store(創(chuàng)建的時候需要傳入一個reducer)
const store = redux.createStore(reducer)
// 訂閱store的修改
store.subscribe(() => {
  console.log("counter:", store.getState().counter);
})

// 派發(fā)action
store.dispatch(action1);
store.dispatch(action2);
store.dispatch(action2);
store.dispatch(action3);
store.dispatch(action4);
完整測試案例:
  1. yarn init
  2. yarn add redux
  3. 創(chuàng)建src目錄末盔,創(chuàng)建index.js
  4. 修改package.json執(zhí)行index.js
“scripts”:{
  "start": "node src/index.js"
}

注意: 從node v13.2.0開始,node才對ES6模塊化提供了支持座慰。
node v13.2.0之前陨舱,需要進行如下操作:
在package.json中添加屬性: "type": "module";
在執(zhí)行命令中添加如下選項:node --experimental-modules src/index.js;
node v13.2.0之后版仔,只需要進行如下操作:
在package.json中添加屬性: "type": "module"

目錄結(jié)構(gòu):
store/index.js

import redux from 'redux';

import reducer from './reducer.js';

const store = redux.createStore(reducer);

export default store;

store/reducer.js

import {
  ADD_NUMBER,
  SUB_NUMBER,
  INCREMENT,
  DECREMENT
} from './constants.js';

const defaultState = {
  counter: 0
}

function reducer(state = defaultState, action) {
  switch (action.type) {
    case ADD_NUMBER:
      return { ...state, counter: state.counter + action.num };
    case SUB_NUMBER:
      return { ...state, counter: state.counter - action.num };
    case INCREMENT:
      return { ...state, counter: state.counter + 1 };
    case DECREMENT:
      return { ...state, counter: state.counter - 1 };
    default:
      return state;
  }
}
export default reducer;

store/actionCreators.js

import {
  ADD_NUMBER,
  SUB_NUMBER,
  INCREMENT,
  DECREMENT
} from './constants.js';

// 寫法一:
// export function addAction(num) {
//   return {
//     type: "ADD_NUMBER",
//     num
//   }
// }

// 寫法二:
// export const addAction = (num) => {
//   return {
//     type: "ADD_NUMBER",
//     num
//   }
// }

// 寫法三:
export const addAction = num => ({
  type: ADD_NUMBER,
  num
});

export const subAction = num => ({
  type: SUB_NUMBER,
  num
});

export const incAction = () => ({
  type: INCREMENT
});

export const decAction = () => ({
  type: DECREMENT
});

store/constants.js

export const ADD_NUMBER = "ADD_NUMBER";
export const SUB_NUMBER = "SUB_NUMBER";
export const INCREMENT = "INCREMENT";
export const DECREMENT = "DECREMENT";
完整react+redux案例:
目錄結(jié)構(gòu).jpg

src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(
    <App />
  document.getElementById('root')
);

src/App.js

import React, { PureComponent } from 'react';

import Home from './pages/home';
import About from './pages/about';

export default class App extends PureComponent {
  render() {
    return (
      <div>
        <Home/>
        <About/>
      </div>
    )
  }
}

src/store/index.js

import { createStore } from 'redux';
iimport reducer from './reducer.js';
const store = createStore(reducer);

export default store; 

其它三個文件store/actionCreators.js游盲、store/reducer.js、store/constants.js不變;
src/store/index.js



pages/about.js

核心:

componentDidMount 中定義數(shù)據(jù)的變化蛮粮,當數(shù)據(jù)發(fā)生變化時重新設(shè)置 counter;
在發(fā)生點擊事件時益缎,調(diào)用store的dispatch來派發(fā)對應(yīng)的action

import React, { PureComponent } from 'react';

import store from '../store';
import {  subAction } from "../store/actionCreators";

export default class About extends PureComponent {
  constructor(props) {
    super(props);

    this.state = {
      counter: store.getState().counter
    }
  }

  componentDidMount() {
    this.unsubscribue = store.subscribe(() => {
      this.setState({
        counter: store.getState().counter
      })
    })
  }

  componentWillUnmount() {
    this.unsubscribue();
  }

  render() {
    return (
      <div>
        <hr/>
        <h1>About</h1>
        <h2>當前計數(shù): {this.state.counter}</h2>
        <button onClick={e => this.decrement()}>-1</button>
        <button onClick={e => this.subNumber(5)}>-5</button>
      </div>
    )
  }

  decrement() {
    store.dispatch(subAction(1));
  }

  subNumber(num) {
    store.dispatch(subAction(num));
  }
}

pages/home.js

import React, { PureComponent } from "react";

import store from "../store";

import { addAction } from "../store/actionCreators";

export default class Home extends PureComponent {
  constructor(props) {
    super(props);

    this.state = {
      counter: store.getState().counter,
    };
  }

  componentDidMount() {
    this.unsubscribue = store.subscribe(() => {
      this.setState({
        counter: store.getState().counter,
      });
    });
  }

  componentWillUnmount() {
    this.unsubscribue();
  }

  render() {
    return (
      <div>
        <h1>Home</h1>
        <h2>當前計數(shù): {this.state.counter}</h2>
        <button onClick={(e) => this.increment()}>+1</button>
        <button onClick={(e) => this.addNumber(5)}>+5</button>
      </div>
    );
  }

  increment() {
    store.dispatch(addAction(1));
  }

  addNumber(num) {
    store.dispatch(addAction(num));
  }
}

代碼在下部分優(yōu)化

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市然想,隨后出現(xiàn)的幾起案子莺奔,更是在濱河造成了極大的恐慌,老刑警劉巖变泄,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件令哟,死亡現(xiàn)場離奇詭異,居然都是意外死亡杖刷,警方通過查閱死者的電腦和手機励饵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來滑燃,“玉大人役听,你說我怎么就攤上這事”砭剑” “怎么了典予?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長乐严。 經(jīng)常有香客問我瘤袖,道長,這世上最難降的妖魔是什么昂验? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任捂敌,我火速辦了婚禮,結(jié)果婚禮上既琴,老公的妹妹穿的比我還像新娘占婉。我一直安慰自己,他們只是感情好甫恩,可當我...
    茶點故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布逆济。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪奖慌。 梳的紋絲不亂的頭發(fā)上抛虫,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天,我揣著相機與錄音简僧,去河邊找鬼建椰。 笑死,一個胖子當著我的面吹牛涎劈,可吹牛的內(nèi)容都是我干的广凸。 我是一名探鬼主播阅茶,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼蛛枚,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了脸哀?” 一聲冷哼從身側(cè)響起蹦浦,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎撞蜂,沒想到半個月后盲镶,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡蝌诡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年溉贿,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片浦旱。...
    茶點故事閱讀 39,688評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡宇色,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出颁湖,到底是詐尸還是另有隱情宣蠕,我是刑警寧澤,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布甥捺,位于F島的核電站抢蚀,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏镰禾。R本人自食惡果不足惜皿曲,卻給世界環(huán)境...
    茶點故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望吴侦。 院中可真熱鬧屋休,春花似錦、人聲如沸妈倔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽盯蝴。三九已至毅哗,卻和暖如春听怕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背虑绵。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工尿瞭, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人翅睛。 一個月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓声搁,卻偏偏與公主長得像,于是被迫代替她去往敵國和親捕发。 傳聞我的和親對象是個殘疾皇子疏旨,可洞房花燭夜當晚...
    茶點故事閱讀 44,573評論 2 353

推薦閱讀更多精彩內(nèi)容