本文簡單的說下redux。html
首先這有張網頁,裏面有文字和內容。redux
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>ReactDemo</title> </head> <body> <div id="title"></div> <div id="content"></div> <div id="root"></div> </body> </html>
如今讓這個網頁經過狀態來顯示標題和內容。函數
let state = { title:{ color:'red', text:'標題' }, content:{ color:'blue', text:'內容' } } function renderTitle(){ let title = document.querySelector('#title'); title.style.background = state.title.color; title.innerHTML = state.title.text; } function renderContent(){ let content = document.querySelector('#content'); content.style.background = state.content.color; content.innerHTML = state.content.text; } //渲染的方法 function render(){ renderTitle(); renderContent(); } render();
這有個問題,首先狀態不能是全局的,也不該該哪一個方法均可以直接更改,這樣作很危險,因此須要提供一個更改狀態的方法,修改這狀態的時候提供一個對象帶有type類型的dispath來修改狀態。ui
//先定義好須要幹那些事情(常量)宏 const CHANGE_TITLE_COLOR = 'CHANGE_TITLE_COLOR'; const CHANGE_CONTENT_TEXT = 'CHANGE_CONTENT_TEXT'; let state = { title:{ color:'red', text:'標題' }, content:{ color:'blue', text:'內容' } } //派發時一個將修改的動做提交過來 //參數{type:'',載荷} function dispatch(action){ //派發的方法,這裏要更改的狀態 switch(action.type){ case CHANGE_TITLE_COLOR: state.title.color = action.color; break; case CHANGE_CONTENT_TEXT : state.content.text = action.text; break; default: break; } } function renderTitle(){ let title = document.querySelector('#title'); title.style.background = state.title.color; title.innerHTML = state.title.text; } function renderContent(){ let content = document.querySelector('#content'); content.style.background = state.content.color; content.innerHTML = state.content.text; } //渲染的方法 function render(){ renderTitle(); renderContent(); } render(); dispatch({type:CHANGE_CONTENT_TEXT,text:'隨便改的'}); render();
可是這麼寫state仍是能被外人調到,因此就有了Redux裏面的store。spa
//先定義好須要幹那些事情(常量)宏 const CHANGE_TITLE_COLOR = 'CHANGE_TITLE_COLOR'; const CHANGE_CONTENT_TEXT = 'CHANGE_CONTENT_TEXT'; function createStore(){ let state = { title:{ color:'red', text:'標題' }, content:{ color:'blue', text:'內容' } } let getState = () => state; //派發時一個將修改的動做提交過來 //參數{type:'',載荷} function dispatch(action){ //派發的方法,這裏要更改的狀態 switch(action.type){ case CHANGE_TITLE_COLOR: state.title.color = action.color; break; case CHANGE_CONTENT_TEXT : state.content.text = action.text; break; default: break; } } //將方法暴露給外面使用 return {dispatch,getState} } let store = createStore(); function renderTitle(){ let title = document.querySelector('#title'); title.style.background = store.getState().title.color; title.innerHTML = store.getState().title.text; } function renderContent(){ let content = document.querySelector('#content'); content.style.background = store.getState().content.color; content.innerHTML = store.getState().content.text; } //渲染的方法 function render(){ renderTitle(); renderContent(); } render(); store.dispatch({type:CHANGE_CONTENT_TEXT,text:'隨便改的'}); render();
dispath寫到庫裏面去多個開發者添加屢次仍是很噁心的,因此改改代碼,將定義狀態和規則的部分抽離到外面去。抽離的狀態叫initState,抽離的規則叫reducer(也就是所謂的管理員)。code
//先定義好須要幹那些事情(常量)宏 const CHANGE_TITLE_COLOR = 'CHANGE_TITLE_COLOR'; const CHANGE_CONTENT_TEXT = 'CHANGE_CONTENT_TEXT'; let initState = { title:{ color:'red', text:'標題' }, content:{ color:'blue', text:'內容' } } //須要兩個參數 老的狀態和新傳遞的動做算出新的狀態 //若是想獲取默認狀態就是調用reducer讓每個規則都不匹配將默認值返回 function reducer(state=initState,action){ //reducer是一個純函數,每次須要返回一個新的狀態 switch(action.type){ case CHANGE_TITLE_COLOR: return {...state,title:{...state.title,color:action.color}}; case CHANGE_CONTENT_TEXT : return {...state,content:{...state.content,text:action.text}}; default: return state; } } function createStore(reducer){ let state let getState = () => state; //派發時一個將修改的動做提交過來 //參數{type:'',載荷} function dispatch(action){ //派發的方法,這裏要更改的狀態 state = reducer(state,action); } dispatch({}) //將方法暴露給外面使用 return {dispatch,getState} } let store = createStore(); function renderTitle(){ let title = document.querySelector('#title'); title.style.background = store.getState().title.color; title.innerHTML = store.getState().title.text; } function renderContent(){ let content = document.querySelector('#content'); content.style.background = store.getState().content.color; content.innerHTML = store.getState().content.text; } //渲染的方法 function render(){ renderTitle(); renderContent(); } render(); store.dispatch({type:CHANGE_CONTENT_TEXT,text:'隨便改的'}); render();
咱們發現一個問題,每次dispath以後都得render一下,ok那麼咱們就整下,其實就是一個發佈訂閱,每次dispath時都調用訂閱號的方法。htm
//先定義好須要幹那些事情(常量)宏 const CHANGE_TITLE_COLOR = 'CHANGE_TITLE_COLOR'; const CHANGE_CONTENT_TEXT = 'CHANGE_CONTENT_TEXT'; let initState = { title:{ color:'red', text:'標題' }, content:{ color:'blue', text:'內容' } } //須要兩個參數 老的狀態和新傳遞的動做算出新的狀態 //若是想獲取默認狀態就是調用reducer讓每個規則都不匹配將默認值返回 function reducer(state=initState,action){ //reducer是一個純函數,每次須要返回一個新的狀態 switch(action.type){ case CHANGE_TITLE_COLOR: return {...state,title:{...state.title,color:action.color}}; case CHANGE_CONTENT_TEXT : return {...state,content:{...state.content,text:action.text}}; default: return state; } } function createStore(reducer){ let state ; let listeners = []; let subscirbe = (listener)=>{ //訂閱 listeners.push(listener); return ()=>{ //再次調用時移除監聽函數。 listeners = listener.filter(fn => fn !== listener); } } let getState = () => state; //派發時一個將修改的動做提交過來 //參數{type:'',載荷} function dispatch(action){ //派發的方法,這裏要更改的狀態 state = reducer(state,action); listeners.forEach(listener=>listener()); } dispatch({}) //將方法暴露給外面使用 return {dispatch,getState,subscirbe} } let store = createStore(); function renderTitle(){ let title = document.querySelector('#title'); title.style.background = store.getState().title.color; title.innerHTML = store.getState().title.text; } function renderContent(){ let content = document.querySelector('#content'); content.style.background = store.getState().content.color; content.innerHTML = store.getState().content.text; } //渲染的方法 function render(){ renderTitle(); renderContent(); } render(); //訂閱 store.subscirbe(render) setTimeout(() => { store.dispatch({type:CHANGE_CONTENT_TEXT,text:'隨便改的'}); }, 2000) //取消訂閱 // let unsub = store.subscirbe(render) // setTimeout(() => { // unsub(); // store.dispatch({type:CHANGE_CONTENT_TEXT,text:'隨便改的'}); // }, 2000);