[TOC]
## 第一版
```
let appState = {
title:{color:'red',text:'標題'}
,content:{color:'green',text:'內容'}
};
// change(appState);
function renderTitle(title){
// appState = null;
let element = document.querySelector('#title');
element.innerHTML = title.text;
element.style.color = title.color;
}
function renderContent(content){
let element = document.querySelector('#content');
element.innerHTML = content.text;
element.style.color = content.color;
}
function renderApp(state){
renderTitle(state.title);
renderContent(state.content);
}
renderApp(appState);
```
問題:
此時狀態是一個全局變量,任何地方都可以改 例如第八行 就會造成毀滅性結果
## 第二版
改進:
增加修改的門檻
```
const UPDATE_TITLE_COLOR = 'UPDATE_TITLE_COLOR';
const UPDATE_TITLE_TEXT = 'UPDATE_TITLE_TEXT';
const UPDATE_CONTENT_COLOR = 'UPDATE_CONTENT_COLOR';
const UPDATE_CONTENT_TEXT = 'UPDATE_CONTENT_TEXT';
// 派發分發的意思
// action動作 動作 描述一下你想干什么,動作是一個普通的js對象,只有一個屬性是必須的 type屬性 其它屬性隨意
function dispatch(action){ //{type:UPDATE_TITLE_COLOR,color:'purple'}
switch(action.type){
case UPDATE_TITLE_COLOR:
appState.title.color = action.color;
break;
case UPDATE_TITLE_TEXT:
appState.title.text = action.text;
break;
case UPDATE_CONTENT_COLOR:
appState.content.color = action.color;
break;
case UPDATE_CONTENT_TEXT:
appState.content.text = action.text;
break;
default:
throw new Error('你發給我的指令我不認識或無法處理!');
}
}
setTimeout(function(){
dispatch({type:UPDATE_TITLE_COLOR,color:'orange'});
dispatch({type:UPDATE_CONTENT_TEXT,text:'新內容'});
renderApp(appState)
},2000);
```
問題:
此時我們仍然可以直接修改appState
## 第三版
改進:
定義一個方法,創建一個倉庫,這個倉庫其實一個對象,只不過可以引用閉包變量
```
function createStore(){
let state = {
title:{color:'red',text:'標題'}
,content:{color:'green',text:'內容'}
};
function dispatch(action){ //{type:UPDATE_TITLE_COLOR,color:'purple'}
switch(action.type){
case UPDATE_TITLE_COLOR:
state.title.color = action.color;
break;
case UPDATE_TITLE_TEXT:
state.title.text = action.text;
break;
case UPDATE_CONTENT_COLOR:
state.content.color = action.color;
break;
case UPDATE_CONTENT_TEXT:
state.content.text = action.text;
break;
default:
throw new Error('你發給我的指令我不認識或無法處理!');
}
}
function getState(){
return JSON.parse(JSON.stringify(state)); //第二層保護
}
return {
getState,dispatch
}
}
let store = createStore();
renderApp(store.getState());
setTimeout(function(){
store.dispatch({type:UPDATE_TITLE_COLOR,color:'orange'});
store.dispatch({type:UPDATE_CONTENT_TEXT,text:'新內容'});
renderApp(store.getState());
},2000);
```
問題:
此時狀態和動作都是寫死的,createStore無法復用
## 第四版
改進:
將dispatch做成了一個對外接口,讓用戶可以自定義動作
并將狀態的初始化綁定在了reducer上的第一個參數上
```
function createStore(reducer){
let state;
let listeners = [];
function dispatch(action){ //{type:UPDATE_TITLE_COLOR,color:'purple'}
state = reducer(state,action); //會返回一個新狀態
}
function getState(){
return JSON.parse(JSON.stringify(state)); //第二層保護
}
dispatch({}); //獲取初始狀態
return {
getState,dispatch,subscribe
}
}
let initState = {
title:{color:'red',text:'標題'}
,content:{color:'green',text:'內容'}
};
reduce處理的意思 處理器 根據老的狀態和拿到的動作 返回新的狀態
let reducer = function(state = initState,action){
switch(action.type){
case UPDATE_TITLE_COLOR:
return {...state,title:{...state.title,color:action.color}};
//return 后自動break
case UPDATE_TITLE_TEXT:
return {...state,title:{...state.title,text:action.text}};
case UPDATE_CONTENT_COLOR:
return {...state,content:{...state.content,color:action.color}};
case UPDATE_CONTENT_TEXT:
return {...state,content:{...state.content,color:action.text}};
default:
return state; //返回老狀態
}
};
let store = createStore(reducer);
renderApp(store.getState());
setTimeout(function(){
store.dispatch({type:UPDATE_TITLE_COLOR,color:'orange'});
store.dispatch({type:UPDATE_CONTENT_TEXT,text:'新內容'});
renderApp(store.getState());
},2000);
```
問題:
仍然需要我們手動調用render刷新
## 第五版
改進:
用發布訂閱來實現自動render刷新
```
function createStore(reducer,preloadedState){
let state = preloadedState;
let listeners = [];
function dispatch(action){ //{type:UPDATE_TITLE_COLOR,color:'purple'}
// 接收到新的動作后u通過老狀態 和新動作 計算出新狀態
state = reducer(state,action); //會返回一個新狀態
// 然后通知所有的監聽函數執行
listeners.forEach(cb => {
console.log(1);
cb();
});
}
function getState(){
return JSON.parse(JSON.stringify(state)); //第二層保護
}
dispatch({}); //獲取初始狀態 //在redux源碼中派發的是名為@@redux/init的東東
// 訂閱,供外界訂閱本倉庫中狀態的變化,如果狀態變化了會執行訂閱的邏輯
function subscribe(listener){
listeners.push(listener);
//會返回一個取消訂閱函數
return function(){
listeners = listeners.filter(item=>item!=listener);
}
}
return {
getState,dispatch,subscribe
}
}
let initState = {
title:{color:'red',text:'標題'}
,content:{color:'green',text:'內容'}
};
// reduce處理的意思 處理器 根據老的狀態和拿到的動作 返回新的狀態
let reducer = function(state = initState,action){
switch(action.type){
case UPDATE_TITLE_COLOR:
return {...state,title:{...state.title,color:action.color}};
//return 后自動break
case UPDATE_TITLE_TEXT:
return {...state,title:{...state.title,text:action.text}};
case UPDATE_CONTENT_COLOR:
return {...state,content:{...state.content,color:action.color}};
case UPDATE_CONTENT_TEXT:
return {...state,content:{...state.content,text:action.text}};
default:
return state; //返回老狀態
}
};
let store = createStore(reducer); //可以傳入初始值 那么此時initStore將會失效
function render(){
renderTitle(store.getState().title);
renderContent(store.getState().content);
}
render();
store.subscribe(render);
let unsubscribe = store.subscribe(render);
setTimeout(function(){
store.dispatch({type:UPDATE_TITLE_COLOR,color:'orange'});
unsubscribe();
store.dispatch({type:UPDATE_CONTENT_TEXT,text:'新內容'});
},2000);
//為了方便action的書寫和避免寫錯,我們一般會寫一個函數來生成對應的action 方便檢查錯誤 有報錯
function updateTitleColor(color){
return {type:UPDATE_TITLE_COLOR,color}
}
```
- 空白目錄
- 01.JSX,了解一下?
- JSX與虛擬DOM
- React
- 02.React文檔精讀(上)`
- React路由
- 關于BrowserRouter
- 關于Route
- 應用
- 權限認證
- case1
- context
- 新context
- 03.React路由
- 04.Diff
- 05.styled-components
- redux設計思想與API
- redux實現1
- 06.redux2
- 06.redux3
- 關于狀態初始化
- saga
- 新版
- 使用saga進行業務邏輯開發
- react-router-redux
- React性能優化
- immutable使用
- 未整理
- FAQ
- 常用中間件
- pureComponent
- 項目相關總結
- antd分尸
- 按需加載
- ReactWithoutJSX
- 我的組件庫
- C領域
- 用戶接口
- htmlType
- style
- show
- conjure
- grid
- inject
- stop
- 內部接口
- 衍生組件
- Button
- 報錯集錦
- ReactAPI
- 類上的那些屬性
- prop-types
- React.createElement
- React.cloneElement
- React.Children和props.children
- react元素和react組件關于作為children方面的那些問題
- react組件與虛擬dom
- ref