Redux 是一个流行的状态管理框架,它可以简化前端应用程序中的数据流程控制。本文将介绍 Redux 的基础知识,并从零开始创建一个简单的 Redux 实现。
Redux 的基础概念
Redux 的核心思想是单一状态树,也就是整个应用程序的状态被存储在一个对象中。这个对象被称为状态存储(store),并且只能通过特定的方式来修改它。这个方式就是通过应用程序中的动作(action)来触发状态修改(state mutation)。
动作是一个携带负载(payload)的简单对象,payload 是传递给状态修改的唯一数据。动作定义了一个描述状态变化的字符和负载的数据对象。例如,以下是一个增加计数器的动作:
{
type: 'ADD_COUNTER',
payload: {
value: 1
}
}当你创建一个动作后,你必须将它发送给状态存储,这称为分派操作(dispatch)。状态存储收到动作后,使用它来计算新的状态。这个新状态更新了整个应用程序的视图。
状态存储是一个包含状态和状态更新逻辑的对象。它由三个基本部分组成:
- 状态。
- 函数:用来获取状态。
- 函数:用来触发状态更新。
现在你已经了解了 Redux 的基础概念,接下来我们将创建一个简单的 Redux 实现。
创建一个简单的 Redux 实现
以下是我们将使用的 Redux 接口,通过这些接口可以创建一个简单的实现。
// www.javascriptcn.com code example
// 创建状态存储
function createStore(reducer, initialState) {
// 获取状态
function getState() {}
// 触发状态更新
function dispatch(action) {}
return {
getState,
dispatch
};
}
// 创建状态更新函数
function combineReducers(reducers) {}
// 订阅状态变化
function subscribe(listener) {}
// 创建动作
function createAction(type, payload) {}我们将逐步实现上述 Redux 接口。
实现创建状态存储的函数
我们将首先实现 createStore 函数。这个函数将接收两个参数:reducer 和 initialState。在这个函数中,我们将创建一个具有 getState 和 dispatch 函数的对象,getState 函数用于获取状态,dispatch 函数用于触发状态更新。
// www.javascriptcn.com code example
function createStore(reducer, initialState) {
let currentState = initialState;
function getState() {
return currentState;
}
function dispatch(action) {
currentState = reducer(currentState, action);
}
return {
getState,
dispatch
};
}现在我们已经创建了一个简单的状态存储。我们可以通过调用这个存储的 getState 函数来获取状态,通过调用 dispatch 函数来更新状态。
实现创建状态更新函数的函数
接下来我们将实现 combineReducers 函数,这个函数将会把多个 reducer 合并为一个单一的 reducer 函数。每个 reducer 函数都可以处理不同的 state field。以下是我们的 combineReducers 函数的代码。
// www.javascriptcn.com code example
function combineReducers(reducers) {
return function(state = {}, action) {
const nextState = {};
for (const key in reducers) {
nextState[key] = reducers[key](state[key], action);
}
return nextState;
};
}这个 combineReducers 函数接收一个对象,对象的每个键值对都是一个 reducer 函数。我们通过遍历 reducers 对象并调用每个 reducer 函数以得到更新后的状态。
实现订阅状态变化的函数
我们可以将单个订阅转换为数组形式,然后循环调用订阅函数以触发回调。
// www.javascriptcn.com code example
function subscribe(listener) {
let listeners = [];
function addListener(newListener) {
listeners.push(newListener);
}
function removeListener(oldListener) {
listeners = listeners.filter(listener => listener !== oldListener);
}
function dispatch(action) {
currentState = reducer(currentState, action);
listeners.forEach(listener => listener());
}
return {
addListener,
removeListener
};
}这个 subscribe 函数将返回一个包含 addListener 和 removeListener 函数的对象。addListener 函数将订阅状态变化,removeListener 函数将从订阅列表中删除这个回调。
实现创建动作的函数
最后我们需要实现 createAction 函数,这个函数将返回一个带有类型和负载的动作。
function createAction(type, payload) {
return {
type,
payload
};
}我们已经创建了一个简单的 Redux 实现。下面是一个完整的示例代码:
// www.javascriptcn.com code example
// 创建状态存储
function createStore(reducer, initialState) {
let currentState = initialState;
let currentListeners = [];
// 获取状态
function getState() {
return currentState;
}
// 触发状态更新
function dispatch(action) {
currentState = reducer(currentState, action);
currentListeners.forEach(listener => listener());
}
// 订阅状态变化
function subscribe(listener) {
currentListeners.push(listener);
return () => {
currentListeners = currentListeners.filter(
currentListener => currentListener !== listener
);
};
}
return {
getState,
dispatch,
subscribe
};
}
// 创建状态更新函数
function combineReducers(reducers) {
return function(state = {}, action) {
const nextState = {};
for (const key in reducers) {
nextState[key] = reducers[key](state[key], action);
}
return nextState;
};
}
// 创建动作
function createAction(type, payload) {
return {
type,
payload
};
}
const ADD_TODO = 'ADD_TODO';
// 创建 reducer
function todosReducer(state = [], action) {
switch (action.type) {
case ADD_TODO:
return [...state, action.payload];
default:
return state;
}
}
// 合并 reducer
const rootReducer = combineReducers({
todos: todosReducer
});
// 创建状态存储
const store = createStore(rootReducer, {});
// 订阅状态变化
store.subscribe(() => {
console.log(store.getState());
});
// 触发动作
store.dispatch(createAction(ADD_TODO, { text: 'Learn Redux' }));在本文中,我们学习了 Redux 的基本概念并创建了一个简单的 Redux 实现。希望这篇文章对你有所帮助。如果你对 Redux 有更深入的了解,你可以继续学习 Redux 的高级概念和中间件。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67d7fa01a941bf7134e3fcd5