我最喜欢的学习方法之一是重新创建一个东西的工作原理。在这篇文章中,我们将通过创建一个简单的版本来学习Redux的基础知识。
Redux实现了什么?
在我们深入研究之前,重要的是要了解Redux完成了什么。Redux是一个状态管理库。它帮助你管理应用程序中的有状态信息。"有状态的信息 "只是一种花哨的说法,即在你的应用程序使用过程中需要持久化和可用的信息。这包括像用户的名字或应用程序是否处于 "光明 "模式或 "黑暗 "模式的东西。
当你的应用程序规模变大时,像Redux这样的状态管理库变得特别有用。许多人认为Redux是React的一部分,或者与React明确相关,但它实际上是自己独立的库,可以与React一起使用,也可以不使用。
Redux的基本原则
Redux背后的基本理念是,你有一个集中的位置来存放你的有状态的信息,并且可以预测地更新状态。为了实现这一点,Redux有以下基本结构。
- 一个状态对象- 状态对象包含你的应用程序的状态信息。这可能是像登录用户的名字和他们是在 "光明 "还是 "黑暗 "模式的信息。
- 行动- 行动是为Redux提供更新状态所需信息的对象。按照惯例,一个行动对象可能有一个
type属性和一个payload属性。如果你想把用户的名字设置为 "Frankie",你的动作可能看起来像这样。{ action: "SET_USER_NAME", payload: "Frankie" } - 一个还原器--还原器是函数。它们接受两个参数。1)当前状态,2)一个动作对象(如上所述)。还原器使用行动对象中提供的信息以及状态的当前版本,并返回状态的新版本。
- 存储器- 存储器是一个允许你访问当前版本的状态的对象,也允许你调度行动来更新该状态。因此,存储对象有两个属性,它们都是函数:
getState和dispatch。
呀,我应该理解这一切吗?
Redux最大的批评之一是它有一个陡峭的学习曲线,所以如果你不理解所有这些,你绝对不应该担心。当我们实施我们自己的、精简的Redux版本时,这些概念应该有望开始点击。而真正有帮助的是在野外实际使用Redux!
推出我们自己的Redux
让我们开始滚动我们自己的Redux!如果你以前使用过Redux,你知道你通常用库中提供的createStore 函数创建你的store 。我们要自己来写这个!
正如我上面提到的,我们的商店需要允许我们通过使用一个getState 函数来访问我们的state 对象。它还必须允许我们进行dispatch 行动。让我们根据这些知识来创建一个骨架式的createStore 函数。
function createStore() {
let state = {}; // Don't know what this is yet
function getState() {
return state;
}
function dispatch(action) {
// Set state based on the action
}
return { getState, dispatch };
}
这是个很好的开始!让我们做一些改进。首先,我们并不总是希望我们的初始state 是一个空对象{} 。相反,我们将让createStore 接受一个叫做initialState 的参数。
接下来,我们的dispatch 函数必须对我们传递给它的action 做一些事情,以便我们的状态可以被更新。如上所述,reducer ,符合这一需求。
还原器是函数。它们接受两个参数。1)当前状态,2)一个动作对象(如上所述)。还原器使用动作对象中提供的信息以及当前版本的状态,并返回一个新版本的状态。
因此,让我们把我们当前的state 对象和action 一起传递给还原器,并把我们的状态变量设置为等于返回值。
这里是我们两个增强功能的实现。
function createStore(reducer, initialState) {
let state = initialState;
function getState() {
return state;
}
function dispatch(action) {
state = reducer(state, action);
}
return { getState, dispatch };
}
这就是我们简化的createStore 函数的最终结果!更有经验的Redux用户可能会注意到,我们省略了createStore 中的第三个参数。这个参数在你进入更高级的Redux时变得很重要,但对于核心原则,我们将坚持使用前两个参数。
在使用我们的createStore 函数之前,我们需要一个reducer 。让我们创建一个可以设置用户名或设置显示模式(亮/暗)的还原器。
正如我们已经讨论过的,我们的reducer 函数将当前的state 和一个action 作为参数,并返回一个新版本的状态。
function reducer(state, action) {
switch (action.type) {
case 'SET_USER_NAME':
return {
...state,
name: action.payload,
};
case 'SET_DISPLAY_MODE':
return {
...state,
displayMode: action.payload,
};
default:
return state;
}
}
让我们来剖析一下我们在这里做了什么。
我们的reducer 需要一个state 参数和一个action 参数。我们有一个switch 语句,它将根据action.type 的值返回不同的东西(记得我们之前讨论过,根据惯例,我们的action 对象有一个type 和一个payload )。
如果action.type 是"SET_USER_NAME" ,那么我们返回一份我们的状态的副本,但是我们用提供的action.payload 覆盖了状态的name 键。反之,如果action.type 是"SET_DISPLAY_MODE" ,我们返回一份我们的状态的副本,但是我们覆盖了displayMode 的键。如果action.type 不是这两个字符串中的一个,我们只是返回我们的状态,不做任何修改。
这就是我们所需要的,我们现在可以带着我们的自家滚动Redux进行测试了
测试运行
下面是我们的自家滚动Redux库的测试运行。请看内联评论,了解具体的运行情况。
// The createStore function we already wrote
function createStore(reducer, initialState) {
let state = initialState;
function getState() {
return state;
}
function dispatch(action) {
state = reducer(state, action);
}
return { getState, dispatch };
}
// The reducer we already wrote
function reducer(state, action) {
switch (action.type) {
case 'SET_USER_NAME':
return {
...state,
name: action.payload,
};
case 'SET_DISPLAY_MODE':
return {
...state,
displayMode: action.payload,
};
default:
return state;
}
}
// Create a new store! This will take our reducer
// and also an initial version of our state.
const initialState = { name: 'Guest', displayMode: 'light' };
const store = createStore(reducer, initialState);
// Change our user's name to "Frankie"
store.dispatch({
type: 'SET_USER_NAME',
payload: 'Frankie',
});
console.log(store.getState());
//{ name: "Frankie", displayMode: "light" }
// Change our display mode to "dark"
store.dispatch({
type: 'SET_DISPLAY_MODE',
payload: 'dark',
});
console.log(store.getState());
//{ name: "Frankie", displayMode: "dark" }
基本上就是这样了
现在我们有了这个漂亮的store 对象,实现了我们想要的一切。
- 我们有一个集中的方式来访问我们的状态信息(通过调用
store.getState())。 - 我们有一个可重复的、可预测的方式,通过调度动作来更新我们的状态信息(通过调用
store.dispatch(action))。
我希望你喜欢这个关于Redux的介绍!