redux核心概念
- components View react頁面
- Action 如果需要修改store的數(shù)據(jù)必須派發(fā)一個動作,它的參數(shù)接收一個對象,對象里面必須要有一個type屬性,表示動作的類型,第二個屬性是你傳入的值
- Reducer 它必須是一個純函數(shù),來處理store數(shù)據(jù)的變化,它接收兩個參數(shù) 一個是state 上一次的數(shù)據(jù), 一個是action . 特別注意的是 不能在這里面修改 state數(shù)據(jù)或者action數(shù)據(jù)
- Store 倉庫 存放state數(shù)據(jù) 它是鏈接action與reducer的橋梁 它的實例對象上有些方法,需要去記住它.
getState() 獲取當前倉庫的 state 數(shù)據(jù)
dispacth(action) 派發(fā)一個動作
subscribe(cb) 監(jiān)聽倉庫數(shù)據(jù)的變化,如果倉庫數(shù)據(jù)有變化,這個回調(diào)函數(shù)就會執(zhí)行
unsubscribe(cb) 取消監(jiān)聽 當倉庫的數(shù)據(jù)發(fā)生改變的時候 subscribe里面的回調(diào)函數(shù)會觸發(fā),重新返回一個函數(shù) 這個函數(shù)需要在 componentswillunmount() {}這個生命周期鉤子函數(shù)里面執(zhí)行,執(zhí)行之后就當組件銷毀的時候,componentswillunmount()生命周期鉤子函數(shù)會執(zhí)行里面的 回調(diào)函數(shù)也會執(zhí)行就取消訂閱了.
- ActionTypes
動作類型常量
- 如果動作類型是一個字符串的話.出現(xiàn)bug 會非常惡心.
- 作用只是解決字符串寫錯之后,調(diào)試bug 非常困難的問題
- ActionsCreates
- 動作生成器
- 就是一個函數(shù)這個函數(shù)調(diào)用之后,返回一個動作的對象
7.安裝 redux
npm install -- save redux || yarn add redux
拆分主reducer, 每個模塊的狀態(tài)都在reducer里面,將每個模塊的狀態(tài)拆分出去,在主的reducer文件中進行引用, 這時就要使用 redux里面的combineReducers方法,這個方法
在 主reducer.js文件中 調(diào)用redux的combineReducers方法,返回一個reducer純函數(shù) 并且把它暴露出去
8. redux的中間件
可以阮一峰學習文檔參考鏈接
http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_two_async_operations.html
中間件主要的作用就是幫助我們實現(xiàn)異步代碼
之前動作一旦被派發(fā),是直接到了 reducer 的純函數(shù)里面,加上中間件之后,動作派發(fā)之后,首先會經(jīng)過中間件來處理,處理之后再到reducer里面去
中間件實現(xiàn)的原理
就是對 store,dispacth 進行重寫
代碼如下:
var next = store.dispacth()
對store 進行重寫
store.dispacth= (action)=>{
默認接收一個 action 對象
console.log("操作之前的數(shù)據(jù)",store.getState());
next(action);
console.log("操作之后的數(shù)據(jù)",store.getState())
}
- 使用第三方提供的redux-logger 中間件
作用主要是在 控制臺 日志輸出的中間件
- 安裝 yarn add redux-logger --save 或 npm i --save redux-logger
在主倉庫中引入: - import logger from 'redux-logger'
在主倉庫的createStore(),傳遞 redux 的 applyMiddleware 調(diào)用即可
applyMiddleware 主要作用就是使用中間件,這個函數(shù)用中間件作為參數(shù)比如: logger thunk saga 一般的話, logger需要放在后面
代碼如下:
import { createStore, applyMiddleware, compose } from "redux";
import reducer from "./reducer";
import logger from "redux-logger";
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(reducer, composeEnhancers(applyMiddleware(logger)));
export default store;
- 使用第三方提供的redux-thunk中間件(讓Redux能夠?qū)崿F(xiàn)異步的代碼)
- 安裝 yarn add redux-thunk --save
- 默認store.dispacth()只能接受一個對象,如果使用了redux-thunk這個中間件 store.dispacth()能接受一個函數(shù)
- 簡單demo如下寫在組件里面
派發(fā)一個異步動作
store.dispatch(() => {
這里寫一個異步的代碼
var url = "http://localhost:9090/shuju";
fetch(url)
.then(response => response.json())
.then(res => {
再派發(fā)一個普通的動作
store.dispatch(initlist(res));
});
});
- 需要將這個方法放在 actionCreate.js 里面
因為在組件頁面中 使用 store.dispacth() 這個方法使用了thunk 之后,里面可以接受一個函數(shù)或者是對象,在這個store.dispacth()參數(shù)的函數(shù) 放到actionCreate.js 里面自定義各一個函數(shù)里面可以發(fā)起ajax網(wǎng)絡(luò)請求 actionCreate里面的函數(shù)經(jīng)過第三方中間件的處理主動接受的參數(shù)有 store里面的 dispacth,getState 這兩個方法,這樣就不需要在重新的引入 store了 可以直接在 dispacth()一個動作給reducer.js
第一種方式組件里面的代碼:
直接派發(fā)一個動作,但是這個動作是在actionCreate里面寫
使用方式1 store.dispatch(initTodoSync); 注意不能加括號 , thunk 會讓initTodoSync執(zhí)行
(加括號的話initTodoSync返回一個undefined 而 store.dispacth 不能接受一個undefined)
第一種方式actionCreate代碼如下:
export const initlist = list => {
return {
type: INIT_LIST, // 主的reducer文件中根據(jù)這個動作的類型,把獲取到的數(shù)據(jù)給store
list
};
};
export const initTodoSync = (dispatch, getState) => {
var url = "http://localhost:9090/shuju";
fetch(url)
.then(response => response.json())
.then(res => {
console.log(res, "獲取成功了嗎?");
console.log(getState());
dispatch(initlist(res)); // 調(diào)用重新初始化倉庫數(shù)據(jù)的函數(shù),把獲取的數(shù)據(jù)傳過去
});
};
第二種方式組件里面的代碼:
store.dispatch(initTodoSync()); //加括號
第二種方式actionCreate代碼如下:
export const initlist = list => {
return {
type: INIT_LIST,
list
};
};
export const initTodoSync = () => {
return (dispatch, getState) => {
var url = "http://localhost:9090/shuju";
fetch(url)
.then(response => response.json())
.then(res => {
console.log(res, "獲取成功了嗎?");
console.log(getState());
dispatch(initlist(res));
});
};
};
redux-thunk 實現(xiàn)的原理:
var next = store.dispacth()
store.dispacth=(action)=>{
if(action && typeof action=== "function"){
//動作是個函數(shù),就會直接執(zhí)行這個動作,并且把兩個參數(shù)傳遞下去
action(state.getState,state.dispacth)
} else{
next(action)
}
}
redux-react
安裝: npm install react-redux || yarn add react-redux
UI組件與容器組件的概念
UI組件: 只是負責數(shù)據(jù)的渲染,不負責數(shù)據(jù)的操作. 不負責跟倉庫打交道,所有的數(shù)據(jù)都是通過props
容器組件: 不負責數(shù)據(jù)渲染, 負責數(shù)據(jù)的操作, 跟倉庫打交道 ,所有的數(shù)據(jù)都是通過倉庫
connect的詳解
connect 方法返回一個高階函數(shù),接收一個組件的參數(shù),生成一個新的組件
connect 方法接收兩個參數(shù) 第一個參數(shù)mapStateToprops (倉庫數(shù)據(jù)發(fā)生改變時,自動執(zhí)行,通過props屬性自動給到組件頁面) 第二個參數(shù)mapDispacthToProps
代碼簡單實現(xiàn)如下
import React, { Component } from "react";
import { connect } from "react-redux";
class Dashboard extends Component {
state = {
name: ""
};
render() {
const { name } = this.props;
return (
<div>
<h2>我的名字{name}</h2>
<button onClick={onTodoClick}>修改我的名字</button>
</div>
);
}
}
const mapStateToprops = state => {
return {
name: this.state.name
};
};
const mapDispacthToprops = () => {
return {
onTodoClick: () => {
dispatch({
type: "SET_VISIBILITY_FILTER",
name: this.state.name
});
}
};
};
export default connect(
mapStateToprops,
mapDispacthToprops
)(Dashboard);