前言
我们在学习react时候,最难啃下来的一块就是redux了。可能现在也有很多伙伴都是停留在只会用的阶段~
我们应该去深入了解一下redux是如何实现的,从而达到灵活运用。
今天,我们就手动实现一个简单的redux。
在实现redux之前,我们需要知道一下几点。
- redux和react没有关系,redux可以用于任何框架中
- connect不属于redux,而属于react-redux
- redux是一个状态管理器。
- 先忘记相关名词 reducer,store,dispatch,middleware等等
实现redux
实现一个简单的状态管理器
redux是一个状态管理器,那什么是状态呢?状态就是数据,比如计数器中count
let state = {
count: 1
}
console.log(state)
state.count = 2;
现在已经完成来状态的访问和使用了。
当时这里有一个很明显的问题:修改count之后,使用了count的地方不能收到通知。我们可以使用发布-订阅模式来解决这个问题。
let state = {
count: 1
}
state.count = 2;
let listeners = [];
// 订阅
function subscribe(listener) {
listeners.push(listener);
}
function changeCount(count) {
state.count = count;
// 当count改变的时候,我们要去通知所有的订阅者
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i];
listener();
}
}
subscribe(()=> {
console.log(state.count)
})
changeCount(5)
现在我们可以看到,我们修改count的时候,会输出相应的count值
现在有两个新的问题摆在我们面前。 这个状态管理器只能管理count,不够通用。 公共的代码要封装起来。
将公用代码封装起来
function createStore(initState) {
let state = initState;
let listeners = [];
// 订阅
function subscribe(listener) {
listeners.push(listener)
}
function changeState(newState) {
state = newState;
// 通知
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i];
listener()
}
}
function getState() {
return state;
}
return {
subscribe,
changeState,
getState,
}
}
// 我们来使用这个状态管理器管理多个状态, counter 和 info 试试
let initState = {
counter: {
count: 0,
},
info: {
name: '',
description: ''
}
}
let store = createStore(initState)
store.subscribe(() => {
let state = store.getState();
console.log(`${state.info.name}: ${state.info.description}`)
});
store.subscribe(() => {
let state = store.getState()
console.log(state.counter.count)
})
store.changeState({
...store.getState(),
info: {
name: '前端',
description: '我们都是前端的爱好者!',
}
})
store.changeState({
...store.getState(),
counter: {
count: 3,
}
})
实现一个有计划的状态管理器
与上一个代码块公用createStore函数
// 我们使用上面的状态管理器来实现一个自增,自减的计算器
let initState = {
count: 0
}
let store = createStore(initState)
store.subscribe(() => {
let state = store.getState()
console.log(state.count)
})
store.changeState({
count: store.getState().count + 1
})
store.changeState({
count: store.getState().count - 1
})
store.changeState({
count: 'abc',
})
这里有个问题,count被改成了字符串abc,因为我们对count的修改没有任何约束,任何地方,任何人都能修改。
我们需要约束,不允许计划外的count修改。我们只允许count自增和自减两种改变方式。
我们分两部来解决这个问题
1、指定一个state修改计划,告诉store,我们的修改计划是什么
2、修改store.changeState方法,告诉它修改state的时候,按照我们的计划修改.
对createStore函数进行修改
function createStore(plan, initState) {
let state = initState;
let listeners = [];
// 订阅
function subscribe(listener) {
listeners.push(listener)
}
function changeState(action) {
state = plan(state, action);
// 通知
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i];
listener()
}
}
function getState() {
return state;
}
return {
subscribe,
changeState,
getState,
}
}
let initState = {
count: 0,
}
function plan(state, action) {
switch(action.type) {
case 'INCREMENT':
return {
...state,
count: state.count + 1
}
case 'DECREMENT':
return {
...state,
count: state.count - 1
}
default:
return state
}
}
let store = createStore(plan, initState)
store.subscribe(() => {
let state = store.getState()
console.log(state)
})
store.changeState({
type: 'INCREMENT'
})
store.changeState({
type: 'DECREMENT'
})
store.changeState({
count: 'abc'
})
到这里,我们就实现了一个最基本的redux了。
其中,plan就是reduer,changeState就是dispatch。