无需 React 即可理解 Redux
我以前总是把React和Redux混为一谈,认为 Redux 必须依附于 React 才能存在。这其实是一个很大的误解,后来我的推文得到了大家的回复才得以澄清
。
在这篇文章中,我将分享如何独立学习 Redux,并解答“Redux 在今天是否仍然适用?”这个问题。
Redux是什么?
根据官方文档,Redux 是 JS 应用的可预测状态容器,让我们来详细解读一下这个定义:
- 可预测性:应用程序的状态变化是可预测的,可以随时间推移进行跟踪(时间旅行)。
- 状态容器:Redux 存储应用程序的状态。应用程序状态是指应用程序所有组件所代表的状态。
- JS 应用:Redux 可以与任何 UI 库(React/Vue/Angular/原生 JavaScript 等)一起使用,这一点我之前并不清楚。
为什么选择 Redux
让我们看看如果没有 Redux,状态管理会有多复杂。 组件内部会管理自己的状态,但当需要在不同组件之间传递状态时,我们需要将状态提升到共同的祖先组件,然后再传递给需要它的组件。 在上面的例子中:名称状态(及其 setter 方法)由组件 C 管理,然后组件 D 需要它,我们将其提升到组件 A。但假设组件 F 也需要它,那么我们需要将其提升到应用程序组件,然后再传递给组件 F。随着应用程序规模的增长,这种状态管理会变得混乱而复杂。
你可能会认为这是一个典型的属性钻探问题,可以通过上下文来解决,那么这里有一篇很棒的文章对此进行了阐述。
现在我们来了解一下 Redux 如何简化上述状态管理流程: Redux 维护着一个集中式store,用于存储应用程序的状态,每个订阅了该 store 的组件都会收到更新后的状态。我们将在下一节详细介绍 Redux 的完整流程。
真实案例
我们每个人一生中至少都会去银行办理一次存款/取款等业务。我们不会直接去银行金库,而是到柜台办理,由银行工作人员为我们操作。我们填写存款/取款申请单并交给柜台人员。让我们用 Redux 的视角来思考一下这个场景:
- 银行金库是存放所有资金的地方。
- 收银员是Reducer,它执行用户操作以更新金库中的资金。
- 客户发送一个描述意图的操作
Redux 的原则
- Store 保存应用程序的状态。整个应用程序的状态存储在单个 store 中的一个对象中。
- Action 描述了应用程序状态的改变,不能直接更新状态对象,状态对象只能由 Redux 更新。
- Reducer 根据 action 执行实际的状态转换。纯 Reducer 接收状态和 action,并返回新的状态。
以下是如何在银行业务场景示例中应用上述概念的方法:
操作
// Actions Objects to withdraw and deposit money
{
type: 'WITHDRAW_MONEY',
payload: 1000
}
{
type: 'DEPOSIT_MONEY',
payload: 500
}
// Action Creator
function withdrawMoney() {
return {
type: "WITHDRAW_MONEY",
payload: 1000,
};
}
减速器
const initialState = {
amount: 5000,
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case "WITHDRAW_MONEY":
return { ...state, amount: state.amount - action.payload };
case "DEPOSIT_MONEY":
return { ...state, amount: state.amount + action.payload };
default:
return state;
}
};
店铺
const redux = require("redux");
const createStore = redux.createStore;
const store = createStore(reducer);
// access to State
console.log("Initial State", store.getState());
//register listeners via subscribe(listener)
const unsubscribe = store.subscribe(() =>
console.log("Update State :", store.getState())
);
//state update via dispatch(action)
store.dispatch(withdrawMoney());
//handles unregistering of listeners by function returned by subscriber
unsubscribe();
回到银行的例子,我们的银行正在扩张,并为企业开设活期账户。由于零售客户和企业客户的需求不同,很难通过单一窗口来管理这两类客户。因此,为了高效地管理所有客户,银行开设了一个名为“活期账户”的新窗口(在 Redux 中相当于一个新的 Reducer)。
const initialState = {
amount: 10000
}
const currentAccountsReducer = (state=initialState , action) => {
switch (action.type) {
case "WITHDRAW_MONEY_CURRENT":
return { ...state, amount: state.amount - action.payload };
case "DEPOSIT_MONEY_CURRENT":
return { ...state, amount: state.amount + action.payload };
default:
return state;
}
}
现在我们需要将这两个 reducer 合并起来创建 store(因为整个应用程序只能有一个 store)。用银行的例子来类比,这可以看作是一种代币自动售货机,它向客户提供用于储蓄/活期账户服务的代币。
const combineReducers = redux.combineReducers;
const createStore = redux.createStore;
const rootReducer = combineReducers({
savings: savingAccountsReducer,
current: currentAccountsReducer,
});
const store = createStore(combineReducers)
每当分发一个 action 时,它都会发送到两个 reducer,但只有一个 reducer 会对其进行处理,另一个 reducer 会忽略它。
中间件
是我们扩展 Redux 功能的方式。它允许我们在 action 被分发之后、到达 reducer 之前插入自定义功能。Redux Logger
就是一个常用的中间件。
const reduxLogger = require("redux-logger");
const logger = reduxLogger.createLogger();
const applyMiddleware = redux.applyMiddleware;
const store = createStore(combineReducers, applyMiddleware(logger))
异步操作
到目前为止,我们看到的都是同步操作——一旦操作被分发,reducer 就会立即更新状态,但在实际场景中,我们必须进行异步 API 调用才能从端点获取数据。
我们来看看如何从 API 获取数据并将其存储在 Redux store 中。
首先,让我们确定应用程序的初始状态。
const initialState = {
loading: false,
error: "",
data: [],
};
由于 dispatch 方法需要异步调用,因此我们需要一个名为“redux-thunk”的中间件来处理从我们的 action creator 返回的函数。
const store = createStore(
rootReducer,
applyMiddleware(thunk)
);
👇 使用 CodeSandbox 练习以上概念:
为了了解如何将 Redux 与 React 结合使用,您可以阅读这篇文章。
文章来源:https://dev.to/bhupendra1011/understanding-redux-without-react-223n

