基础Redux实现
Redux的强大之处也由于它的简洁,我们甚至可以用几行代码来实现一个简易的Redux生态。
Redux将所有数据都存储再一个地方,即store,因此,我们要实现:
- 事件最终会修改state
- 监听state的改变好让我们能够改变UI
上述的第1点我们可以分成两个小部分来实现:
- 在action生成时通知store
- 为store实现修改state的逻辑(即代码)
根据以上描述,我们只使用html和javascript,不借助外部库,用Flux概念来构建一个简单的计数器,使用按钮可以增加和减少计数值。
index.html
<div>
计数:
<span id="counter"></span>
</div>
<button id="inc">增加</button>
<button id="dec">减少</button>
使用state来保存计数值
counter.js
let state = {
counter: 3
}
在每个按钮的点击事件上来生成action,并使用dispatch(action)函数来分发
document.getElementById('inc').onclick = () => dispatch('INC')
document.getElementById('dec').onclick = () => dispatch('DEC')
// 在redux中 action中必须有tpe属性 在这里我们先简写 只传入一个代表增加或减少的字符串
function dispatch(action){
// 待定 请继续阅读之后的部分
}
其次,我们需要定义更新html页面的代码
function updateView(){
document.getElementById('counter').innerText = state.counter
}
由UI显示state中的值,即counter,那么我们需要在每次state变化时通知updateView()来及时更新html页面上的内容
subscribe(updateView)
// subscribe函数还未定义 在这里先使用 请继续阅读
至此,我们已经创建了计数器的基本结构。使用state来存储计数器的值,updateView函数来更新html,定义了两个函数dispatch和subscribe函数来分发action和监听state改变并通知updateView函数(即调用)。
但我们还没有实现处理事件的过程,这个简易Redux是如何在获得action,经历一些步骤后,来达到更改html的呢?为此我们还需要一个reducer函数,接受当前的state和action,来返回一个新的state,再用新的state来渲染html。
由于我们的action没有type属性,只是一个代表了增加或减少的字符串,我们的reducer实现如下
function reducer(state, action){
switch(action){
case 'INC':
return { ...state, counter: state.counter + 1 }
case 'DEC':
return { ...state, counter: state.counter - 1 }
default:
return state
}
}
重要的是,在state有变化时,reducer必须创建一个新的state,在新的state上根据action做出改动,并返回新的state。(新的state在js中可理解为不同的引用,state为一个object,js中两个结构和键值完全相同的object并不相等,因为他们在===比较时用的时引用,即内存地址)
用如下方式来改变state时错误的,因为state的内存地址没有变,store并不能检测到state的改变,随后会说明原因
state.counter = state.counter + 1
dispatch函数调用reducer函数来获取新的state,并通知updateView改变html
function dispatch(action){
const newState = reducer(state, action)
if(newState !== state){
state = newState
listeners.forEach(listener => listener())
}
}
在if判断中,我们通过比较内存地址来得知state发生了改变,listeners为一个数组,里面包含了在state有变动时需要触发的函数,比如updateView
const listeners = []
function subscribe(callback){
listeners.push(callback)
}
之前,我们已经用subscribe监听了updateView函数。至此,我们的简易Redux计数器完成了。我们可以点击按钮来增加和减少计数值。
document.getElementById('counter').innerText = document.getElementById('counter').innerText + 1
使用如上代码或许也能轻松实现该效果,但随着我们的应用逐渐扩大,所涉及的改动也越来越多,Flux设计模式的优势也将会逐渐凸显。
网友评论