Redux原理理解(一)

  1. 1. createStore的简单实现

前言

  • reducer和react-reducer是两个概念,建议看看阮一峰-redux,阮一峰-react-redux,关于使用我也在探索中

  • REDUX是用来进行状态统一管理的组件

  • REACT-REDUX是把REDUX进一步封装,使其在REACT项目中可以快速应用

  • 这篇文章并不是直接分析源码,而是从简单的ES6代码到模拟react原理,一步步分析其思想原理,建议自己敲一遍,高手可以直接看文章最后的原理部分

这里一共有六部分代码,循序渐进: 第一次

1
2
3
4
5
6
7
8
9
10
11
12
//一个普通的render函数
function render() {
let titleState={text:"前端学习之路",color:"red"};
let contentState={text:"CSS,HTML,JS,NODE,VUE,REACT",color:"green"};
let title=document.getElementById("title");
title.innerHTML=titleState.text;
title.style.color=titleState.color;
let content=document.getElementById("content");
content.innerHTML=contentState.text;
content.style.color=contentState.color;
}
render();

第二次

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//将title和content拿出来,模拟组件
function Title(titleState) {
let title=document.getElementById("title");
title.innerHTML=titleState.text;
title.style.color=titleState.color;
}
function Content(contentState) {
let content=document.getElementById("content");
content.innerHTML=contentState.text;
content.style.color=contentState.color;
}
function render() {
let titleState={text:"前端学习之路",color:"red"};
let contentState={text:"CSS,HTML,JS,NODE,VUE,REACT",color:"green"};
Title(titleState);
Content(contentState);
}
render();

第三次

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// 将状态统一管理
//上一次的state,任何组件都可以拿来修改,容易混乱,先提取出来,只有dispatch方法才可以修改state
// state=>对照阮一峰的博客理解其概念
// 载荷:作用于state使其发生改变
// 修改状态不可以直接修改 直接调用dispatch去修改状态

function createStore() {
let state={
titleState:{text:"前端学习之路",color:"red"},
contentState:{text:"CSS,HTML,JS,NODE,VUE,REACT",color:"green"}
};
//要求 传一个参数 action 一个对象{type:"修改某个状态的标志",其他的参数是修改后的值(载荷)}
function dispatch(action) {
switch (action.type){
case TITLE_CHANGE_TEXT:
state={...state,titleState:{...state.titleState,text:action.text}};
break;
case TITLE_CHANGE_COLOR:
state={...state,titleState:{...state.titleState,color:action.color}};
break;
case CONTENT_CHANGE_TEXT:
state={...state,contentState:{...state.contentState,text:action.text}};
break;
}
}
//为了防止 state泄漏 外面可以修改 ,需要一个跟state长的一样的对象 但是地址不一样[深拷贝]
let getState=()=>(JSON.parse(JSON.stringify(state)));
return {dispatch,getState}
}

const TITLE_CHANGE_TEXT="title_change_text";
const TITLE_CHANGE_COLOR="title_change_color";
const CONTENT_CHANGE_TEXT="content_change_text";

//创建容器
let store=createStore();
function Title() {
let title=document.getElementById("title");
//如果是state.state.xxx=xxx,容易使状态管理混乱,只能通过store.getState()方法修改,因为并不是真实的地址值
title.innerHTML=store.getState().titleState.text;
title.style.color=store.getState().titleState.color;
}
function Content() {
let content=document.getElementById("content");
content.innerHTML=store.getState().contentState.text;
content.style.color=store.getState().contentState.color;
}
function render() {
Title();
Content();
}

setTimeout(()=>{
store.dispatch({type:TITLE_CHANGE_TEXT,text:"其实前端很好玩~"});
store.dispatch({type:TITLE_CHANGE_COLOR,color:"blue"});
store.dispatch({type:CONTENT_CHANGE_TEXT,text:"html+css+js+node+vue+react"});
render();
},3000);
render();
  • createStore =>用来生成store,store用来存储数据
  • store.getState =>当前时刻的state
  • action =>一个对象,是View(用户)发出的通知,表示state要发生变化了
  • store.dispatch()是 View 发出 Action 的唯一方法

理清楚上面的概念后,我们看看还需要什么

第四次

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
//createStore是redux提供的一个函数,不可能修改其源码,状态应该拿出来

function createStore(reducer) {
let state;
//默认第一次先执行一个dispatch
dispatch({});//为了防止 action是一个undefined 而undefined.type就会报错
function dispatch(action) {
//reducer作用就是修改 state用的
state=reducer(state,action)
}
let getState=()=>(JSON.parse(JSON.stringify(state)));
return {dispatch,getState}
}

const TITLE_CHANGE_TEXT="title_change_text";
const TITLE_CHANGE_COLOR="title_change_color";
const CONTENT_CHANGE_TEXT="content_change_text";
let initState={
titleState:{text:"前端学习之路",color:"red"},
contentState:{text:"CSS,HTML,JS,NODE,VUE,REACT",color:"green"}
};

function reducer(state=initState,action) {
switch (action.type){
case TITLE_CHANGE_TEXT:
//return 一个修改后的state
return {...state,titleState:{...state.titleState,text:action.text}};
break;
case TITLE_CHANGE_COLOR:
return {...state,titleState:{...state.titleState,color:action.color}};
break;
case CONTENT_CHANGE_TEXT:
return {...state,contentState:{...state.contentState,text:action.text}};
break;
}
//这里一定不要忘了返回
return state;
}
//创建容器 传一个参数 函数
let store=createStore(reducer);

function Title() {
let title=document.getElementById("title");
title.innerHTML=store.getState().titleState.text;
title.style.color=store.getState().titleState.color;
}
function Content() {
let content=document.getElementById("content");
content.innerHTML=store.getState().contentState.text;
content.style.color=store.getState().contentState.color;
}
function render() {
Title();
Content();
}

setTimeout(()=>{
store.dispatch({type:TITLE_CHANGE_TEXT,text:"前端其实很好玩~"});
store.dispatch({type:TITLE_CHANGE_COLOR,color:"blue"});
store.dispatch({type:CONTENT_CHANGE_TEXT,text:"html+css+js+node+vue+react"});
render();
},3000);
render();
  • reducer =>一个函数,它接受 Action 和当前 State 作为参数,返回一个新的 State。
  • reducer 把修改容器中状态的行为操作统一放到一起进行统一管理

第五次

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
//订阅事件
function createStore(reducer) {
let state,listener=[];
dispatch({});
function dispatch(action) {
state=reducer(state,action);
//依次让订阅的方法执行
listener.forEach(item=>item());
}
let subscribe=(fn)=>{
listener=[...listener,fn];
//返回一个函数 取消订阅
return ()=>{
//将数组中的fn删除
listener=listener.filter(item=>item!=fn);
}
};
let getState=()=>(JSON.parse(JSON.stringify(state)));
return {dispatch,getState,subscribe}
}

const TITLE_CHANGE_TEXT="title_change_text";
const TITLE_CHANGE_COLOR="title_change_color";
const CONTENT_CHANGE_TEXT="content_change_text";
let initState={
titleState:{text:"前端",color:"red"},
contentState:{text:"CSS,HTML,JS,NODE,VUE,REACT",color:"green"}
};
function reducer(state=initState,action) {
switch (action.type){
case TITLE_CHANGE_TEXT:
//return 一个修改后的state
return {...state,titleState:{...state.titleState,text:action.text}};
break;
case TITLE_CHANGE_COLOR:
return {...state,titleState:{...state.titleState,color:action.color}};
break;
case CONTENT_CHANGE_TEXT:
return {...state,contentState:{...state.contentState,text:action.text}};
break;
}

return state;
}

let store=createStore(reducer);

store.subscribe(render);
let unsubscribe=store.subscribe(()=>{
console.log("KK好漂亮");
});
unsubscribe();

function Title() {
let title=document.getElementById("title");
title.innerHTML=store.getState().titleState.text;
title.style.color=store.getState().titleState.color;
}
function Content() {
let content=document.getElementById("content");
content.innerHTML=store.getState().contentState.text;
content.style.color=store.getState().contentState.color;
}
function render() {
Title();
Content();
}

setTimeout(()=>{
store.dispatch({type:TITLE_CHANGE_TEXT,text:"前端其实很好玩~"});
store.dispatch({type:TITLE_CHANGE_COLOR,color:"blue"});
store.dispatch({type:CONTENT_CHANGE_TEXT,text:"html+css+js+node+vue+react"});
},3000);
render();
  • subscribe =>设置监听函数,一旦 State 发生变化,就自动执行这个函数。
  • 发布订阅这个不难理解

最后,放大招:

createStore的简单实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const createStore = (reducer) => {
let state;
let listeners = [];

const getState = () => state;

const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach(listener => listener());
};

const subscribe = (listener) => {
listeners.push(listener);
return () => {
listeners = listeners.filter(l => l !== listener);
}
};

dispatch({});

return { getState, dispatch, subscribe };
};

等等,还有:

combineReducers的简单实现

1
2
3
4
5
6
7
8
9
function combineReducers(reducers) {
return (state={},action)=>{
let obj={};
for (let key in reducers){
obj[key]=reducers[key](state[key],action)
}
return obj;
}
}
  • combineReducers()做的就是产生一个整体的 Reducer 函数。该函数根据 State 的 key 去执行相应的子 Reducer,并将返回结果合并成一个大的 State 对象。

  • 可以看下一篇的应用来理解~

Comment