一.Redux 解析
1).統一數據管理
將所需的數據提取到state中統一進行管理。當渲染後我們希望更改狀態,封裝更改狀態的方法(dispatch)
2).實現dispatch
不要直接更改狀態而是使用dispatch方法進行狀態的更改,派發一個帶有type的屬性來進行狀態的更改,但是依然無法阻止用戶更改狀態.
3).createStore的實現
將狀態放到了createStore函數中,目的是隔離作用域,並且再內部返回深度克隆的對象,這樣用戶無法再通過外界更改狀態。但是狀態應該由我們自身來控制,應該是外界傳入的,所以要將狀態拿出createStore。並且判斷的邏輯也應該由我們自己來編寫
4).reducer的實現
我們已將需要自己處理的邏輯提取出來,但是我們每次dispatch時都需要自己觸發視圖的更新,我們希望採用發佈訂閱來實現。
5).訂閱函數
我們redux中常用的方法已經封裝完成我們將封裝好的邏輯抽離成redux.js
二.Redux深入
2.1 redux文件拆分
store
│ action-types.js
│ index.js
│
├─actions
│ counter.js
│
└─reducer
counter.js
action-types用來存放需要的常量
counter中存放reducer的邏輯
store中的index文件用來創建store
action文件夾中的counter,用來生成對應組件的action對象
2.2 實現多個counter
在redux中只能擁有一個store所以我們需要將多個狀態進行合併,狀態是通過reducer返回的,所以我們可以將多個reducer進行合併達到合併狀態的目的。
│ index.js
│ redux.js
│
├─components
│ counter1.js
│ counter2.js
│
└─store
│ action-types.js
│ index.js
│
├─actions
│ counter1.js
│ counter2.js
│
└─reducer
counter1.js
counter2.js
index.js
action-types新增counter2處理的常量
對應的counter2中的action也進行更改
三. React-Redux
1.爲什麼需要高階組件
從本地存儲中獲取數據放到輸入框內的邏輯應該就是公用邏輯。這時我們就要使用高階組件,也就是將組件在原有的基礎上進行包裝。
2.實現高階組件
我們將公共的邏輯拿到外層組件,處理好後以屬性的方式傳遞給原本的組件,爲此高階組件就是一個 React 組件包裹着另外一個 React 組件
3.context的用法
react是單向數據流,我們想傳遞數據需要一層層向下傳遞,數據傳遞變得非常麻煩,我們可以用context實現數據的交互
1) 父 childContextTypes getChildContext函數
2) 子 contextTypes
import React from 'react';
import ReactDOM from 'react-dom';
import Counter from "./components/Counter";
import store from './store/index';
import {Provider} from 'react-redux';
ReactDOM.render(
<Provider store={store}>
<Counter/>
</Provider>,window.root);
class Counter extends React.Component {
render(){
return <div>
數量:{this.props.number}
<button onClick={()=>{this.props.add(1)}}>+</button>
<button onClick={()=>{this.props.minus(1)}}>-</button>
</div>
}
}
export default connect(state=>({...state}),dispatch=>({
add:(amount)=>{dispatch(actions.add(amount))},
minus:(amount)=>{dispatch(actions.minus(amount))}
}))(Counter)
四.MiddleWare的使用
1.logger中間件
在控制檯查看更改前後的狀態
2.實現redux-thunk中間件
實現派發異步動作,actionCreator可以返回函數,可以把dispatch的權限交給此函數
3.實現redux-promise中間件
返回一個實例 ,支持異步請求 看resolve reject情況
五. Redux 源碼仿寫
<div id="title"></div>
<div id="content"></div>
const CHANGE_TITLE_TEXT = "CHANGE_TITLE_TEXT";
const CHANGE_CONTENT_COLOR = "CHANGE_CONTENT_COLOR";
function createStore(reducer) {
let state;
let listeners = [];
let getState = () => JSON.parse(JSON.stringify(state));
function dispatch(action) {
state = reducer(state, action);
listeners.forEach(item => {
if (typeof item === "function") {
item();
}
})
}
dispatch({});
function subscribe(fn) {
listeners.push(fn);
return () => {
listeners = listeners.filter(item => item !== fn);
}
}
return {
getState,
dispatch,
subscribe
}
}
let initState = {
title: { color: "red", text: "xxWOxx" },
content: { color: "yellow", text: "qqNIqq" }
};
function reducer(state = initState, action) {
switch (action.type) {
case CHANGE_TITLE_TEXT:
return { ...state, title: { ...state.title, text: action.text } };
case CHANGE_CONTENT_COLOR:
return { ...state, content: { ...state.content, color: action.color } }
}
return state;
}
let store = createStore(reducer);
function renderTitle() {
let title = document.getElementById("title");
title.innerHTML = store.getState().title.text;
title.style.color = store.getState().title.color;
}
function renderContent() {
let content = document.getElementById("content");
content.innerHTML = store.getState().content.text;
content.style.color = store.getState().content.color;
}
function renderApp() {
renderTitle();
renderContent();
}
renderApp();
setTimeout(function () {
store.dispatch({ type: CHANGE_TITLE_TEXT, text: "好好學習" });
store.dispatch({ type: CHANGE_CONTENT_COLOR, color: "blue" })
}, 2000)