把之前學習redux的手寫學習筆記分享出來一下,方便大家理解redux思想,畢竟前端工程師裡面都說,
初級前端和中級前端的區別就是是否懂設計模式和麵向物件
這個是將redux思想的一個拆分, 將 redux 拆分成 5 部分,最終拼成一個react redux,
為什麼使用react redux ?
有了redux之後 state不再是誰都可以任意呼叫setState修改的資料了,
react沒有redux 和 有redux的核心區別**
react: 通過 setState修改state資料,再執行渲染;
react-redux: 通過 dispatch來判斷是否執行setState,dispatch檢測通過,執行setState函式, 否則不予執行;
1. 引入dispatch管理對setState的呼叫
<div id="title"></div>
<div id="contents"></div>
<script>
// 渲染模組
function render() {
document.getElementById('title').innerHTML = state.title;
document.getElementById('contents').innerHTML = state.content;
}
//資料模組
var state = {
title: '新的標題',
content: '新的內容'
}
//初次渲染執行
render();
//更改資料模組 ** 更改後觸發資料渲染
function setState(newState) {
this.state = {
...state,
...newState
}
render()
}
</script>
複製程式碼
下面這部分是redux思想的和體現方式, 通過dispath判斷引數的type是否合法, 合法才可以可以呼叫setState
<script>
// 管理模組, 想要觸發資料改變請執行這個函式, 並且要給指定的type, 否則不執行setState
var dispatch = function (action) {
switch (action.type) {
case 'CHANGE_TITLE': // 傳過來的type正確才能setState
setState({
title: action.newTitle
})
break;
default:
break;
}
}
//修改資料呼叫dispatch函式, 只有裡面的json的type經過了dispatch檢測才能執行相應的setState
dispatch(
{
type: 'CHANGE_TITLE',
newTitle: '我是經過dispatch函式允許修改後的新標題'
}
)
</script>
複製程式碼
2. 引入subscriber
<div id="title"></div>
<div id="contents"></div>
<script>
function render() {
document.getElementById('title').innerHTML = state.title;
document.getElementById('contents').innerHTML = state.content;
}
var state = {
title: '新的標題',
content: '新的內容'
}
render()
複製程式碼
建立陣列listeners, 引入訂閱subscriber 函式,該函式向陣列中訂閱(push)新的事件,比如render渲染函式,在成功觸發setState後,會對listensers陣列裡面的函式依次執行。
var dispatch = function (action) {
switch (action.type) {
case 'CHANGE_TITLE':
state = {
...state,
title:action.newTitle
}
break;
default:
break;
}
listeners.forEach(e=>e()) //依次執行陣列中訂閱的事件
}
var listeners = []; //這個陣列放setState之後執行的事件,
var subscribe = function(listener){ //用subscriber函式把事件push到事件陣列中
listeners.push(listener)
}
subscribe(render) // 陣列中放入render函式
dispatch(
{
type: 'CHANGE_TITLE',
newTitle: '我是經過dispatch函式允許修改後的新標題'
}
)
</script>
</body>
複製程式碼
3. 初步封裝 createStore
div id="title"></div>
<div id="contents"></div>
<script>
//渲染函式
function render(state) {
document.getElementById('title').innerHTML = state.title;
document.getElementById('contents').innerHTML = state.content;
}
//store 核心部分
var createStore = function () {
//state資料
var state = {
title: '這是一個標題',
content: '這是一段內容'
}
//執行函式倉庫
var listeners = [];
//獲取state資料
var getState = function () {
return state;
}
//dispatch監控 type是否合法,合法才觸發setState函式
var dispatch = function (action) {
switch (action.type) {
case 'CHANGE_TITLE':
state = {
...state,
title: action.newTitle
}
break;
default:
break;
}
listeners.forEach(e => e())
}
//事件訂閱函式
var subscribe = function (listener) {
listeners.push(listener)
}
// 暴露呼叫介面
return {
dispatch,
subscribe,
getState
}
}
//呼叫部分
//建立例項化物件
var store = createStore();
//解構獲取三個介面函式
var { subscribe, dispatch, getState } = store;
//訂閱事件
subscribe(() => render(getState()));
//請求dispatch改變狀態
dispatch(
{
type: 'CHANGE_TITLE',
newTitle: '我是經過dispatch函式允許修改後的新標題'
}
)
render(getState())
</script>
複製程式碼
但是這個createStore函式存在不純的問題,含有定好的state 和 dispatch,接下來就是對該函式進行提純處理。
4. createStore函式提純處理,讓createStore 和 state,setState相分離 , 將state和setState放入appReducer函式中
<div id="title"></div>
<div id="contents"></div>
<script>
//store 核心部分
var createStore = function () {
// 將state設定為 null;
var state = null
var listeners = [];
var dispatch = function (action) {
//呼叫dispatch時, 執行appReducer做判斷
state = appReducer(state, action);
listeners.forEach(e => e());
}
//呼叫dispatch初始化state,獲取appReducer中的預設state。
dispatch({})
var subscribe = function (listener) {
listeners.push(listener)
}
var getState = function () {
return state;
}
//暴露介面
return {
dispatch,
subscribe,
getState
}
}
var appReducer = function (state, action) {
//初始化store中的state
//因為state初始值為null
if (!state) {
return {
title: '這是一個標題',
content: '這是一段內容'
}
}
//更新state
switch (action.type) {
case 'CHANGE_TITLE':
return {
...state,
title: action.newTitle
}
break;
default:
return state;
}
}
var store = createStore();
var { subscribe, dispatch, getState } = store;
subscribe(() => render(getState()))
dispatch(
{
type: 'CHANGE_TITLE',
newTitle: '我是經過dispatch函式允許修改後的新標題'
}
)
function render(state) {
document.getElementById('title').innerHTML = state.title;
document.getElementById('contents').innerHTML = state.content;
}
//呼叫部分
render(getState())
</script>
複製程式碼
此時 createStore依然不是一個純函式, 依然無法獨立, 因為裡面有寫死的appReducer函式的執行;
5. 徹底讓createStore變成純建構函式 , appReducer作為引數傳入到createStore。
// 現在已經是非常乾淨的純建構函式了
function createStore(appReducer) {
state = null;
var listeners = [];
function dispatch(action) {
state = appReducer(state, action)
listeners.map(e => e())
}
dispatch({})
function getState() {
return state
}
function subscribe(listener) {
listeners.push(listener);
}
return {
dispatch,
getState,
subscribe
}
}
// appReucer 函式
function appReducer(state, action) {
//初始化資料
if (!state) {
return {
title: '你好',
content: '歡迎光臨'
}
}
switch (action.type) {
case 'CHANGE_TITLE':
return {
...state,
title: action.newTitle
}
break;
default:
break;
}
}
//使用createStore部分
var store = createStore(appReducer);
var { dispatch,
getState,
subscribe } = store;
subscribe(() => render(getState()))
dispatch(
{
type: "CHANGE_TITLE",
newTitle: '我是經過dispatch函式允許修改後的新標題'
}
)
function render(state) {
document.getElementById('title').innerHTML = state.title;
document.getElementById('content').innerHTML = state.content;
}
render(getState());
複製程式碼