本文简单的说下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来修改状态。
//先定义好需要干那些事情(常量)宏 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。
//先定义好需要干那些事情(常量)宏 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(也就是所谓的管理员)。
//先定义好需要干那些事情(常量)宏 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时都调用订阅号的方法。
//先定义好需要干那些事情(常量)宏 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);