转载自 Kingsley Silas. Understanding How Reducers are Used in Redux. Oct 24, 2019css
reducer是一个决定应用程序状态变化的函数。它使用它接收到的动做来肯定这种变化。咱们有一些工具,好比Redux,能够帮助管理应用程序在单一存储中的状态变化,使它们的行为一致。redux
为何咱们在谈论reducers的时候要提到Redux?Redux在很大程度上依赖于reducer函数,这些函数利用上一个状态和一个动做来执行下一个状态。markdown
咱们将在这篇文章中直接关注reducer。咱们的目标是熟悉使用reducer函数,这样咱们就能够看到它是如何用来更新应用程序的状态的--并最终理解它们在状态管理器中扮演的角色,好比Redux。网络
状态变化是一个基于用户的交互,甚至是相似网络请求的东西。若是应用程序的状态是由Redux管理的,那么变化就发生在reducer函数中--这是惟一发生状态变化的地方。reducer函数利用应用程序的初始状态 initial state和一些叫作动做 action的东西,来决定新的状态 new state会是什么样子。app
若是咱们在数学课上,咱们能够说。ide
initial state + action = new state
复制代码
从实际的reducer函数来看,是这样的。函数
const contactReducer = (state = initialState, action) => {
// Do something
}
复制代码
咱们从哪里得到初始状态和行为?这些都是咱们要定义的东西工具
传递给reducer函数的参数state
必须是应用程序的当前状态。在这个例子中,咱们把它称为initialState
,由于它将是第一个(也是当前)状态,而在它以前不会有任何东西。oop
contactReducer(initialState, action)
复制代码
比方说,咱们应用的初始状态是一个空的联系人列表,咱们的操做是向列表中添加一个新的联系人。ui
const initialState = {
contacts: []
}
复制代码
这就建立了咱们的InitialState
,它等于咱们在reducer数中须要的参数state
。
一个action
是一个包含两个键及其值的对象。在reducer中发生的状态更新老是依赖于action.type
的值。在这个场景中,咱们要演示的是当用户试图建立一个新的联系人时发生的事情。因此,让咱们把action.type
定义为NEW_CONTACT
。
const action = {
type: 'NEW_CONTACT',
name: 'John Doe',
location: 'Lagos Nigeria',
email: 'johndoe@example.com'
}
复制代码
一般有一个payload
值,包含用户发送的内容,将用于更新应用程序的状态。须要注意的是,action.type
是必需的,但 action.payload
是可选的。使用payload
为action对象的外观带来了必定程度的结构性。
状态的意思是,它是不可变的,也就是说不该该直接改变它。要建立一个更新的状态,咱们能够利用Object.assign或者选择spread操做符。
const contactReducer = (state, action) => {
switch (action.type) {
case 'NEW_CONTACT':
return Object.assign({}, state, {
contacts: [
...state.contacts,
action.payload
]
})
default:
return state
}
}
复制代码
在上面的例子中,咱们使用了Object.assign()
来确保咱们不直接改变状态值。相反,它容许咱们返回一个新的对象,这个对象充满了传递给它的状态和用户发送的有效载荷。
要使用Object.assign()
,重要的是第一个参数是一个空对象。传递状态做为第一个参数会致使它被突变,这也是咱们要避免的,以保持一致性。
object.assign()
的替代方法是使用spread操做符,像这样。
const contactReducer = (state, action) => {
switch (action.type) {
case 'NEW_CONTACT':
return {
...state, contacts:
[...state.contacts, action.payload]
}
default:
return state
}
}
复制代码
这确保了在咱们将新项目追加到底部时,入库状态保持不变。
前面,咱们注意到,发生的更新取决于action.type
的值。switch语句根据action.type
的值,有条件地决定咱们要处理的更新类型。
这意味着一个典型的reducer会是这样的。
const addContact = (state, action) => {
switch (action.type) {
case 'NEW_CONTACT':
return {
...state, contacts:
[...state.contacts, action.payload]
}
case 'UPDATE_CONTACT':
return {
// Handle contact update
}
case 'DELETE_CONTACT':
return {
// Handle contact delete
}
case 'EMPTY_CONTACT_LIST':
return {
// Handle contact list
}
default:
return state
}
}
复制代码
重要的是,当action对象中指定的 "action.type "的值与reducer中的值不匹配时,咱们要返回咱们的 "default "状态--好比说,若是因为某些未知的缘由,action看起来像这样。
const action = {
type: 'UPDATE_USER_AGE',
payload: {
age: 19
}
}
复制代码
因为咱们没有这种动做类型,因此咱们但愿返回状态中的内容(应用程序的当前状态)来代替。总之咱们不肯定用户此刻想达到什么目的。
下面是我在React中实现reducer函数的一个简单例子。
const initialState = {
contacts: [{
name: 'Vic Henry',
age: 30
}]
};
const contactReducer = (state = initialState, action) => {
switch (action.type) {
case "NEW_CONTACT":
return Object.assign({}, state, {
contacts: [...state.contacts, action.payload]
});
default:
return state;
}
};
class App extends React.Component {
constructor(props) {
super(props);
this.name = React.createRef();
this.age = React.createRef();
this.state = initialState;
}
handleSubmit = e => {
e.preventDefault();
const action = {
type: "NEW_CONTACT",
payload: {
name: this.name.current.value,
age: this.age.current.value
}
};
const newState = contactReducer(this.state, action);
this.setState(newState);
};
render() {
const { contacts } = this.state;
return (
<div className="box"> <div className="content"> <pre>{JSON.stringify(this.state, null, 2)}</pre> </div> <div className="field"> <form onSubmit={this.handleSubmit}> <div className="control"> <input className="input" placeholder="Full Name" type="text" ref={this.name} /> </div> <div className="control"> <input className="input" placeholder="Age" type="number" ref={this.age} /> </div> <div> <button type="submit" className="button">Submit</button> </div> </form> </div> </div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
复制代码
你能够看到,我没有使用Redux,但这与Redux使用reducer来存储和更新状态变化的方式很是相同。主要的状态更新发生在reducer函数中,它返回的值设置了应用程序的更新状态。
想试一试吗?你能够扩展reducer函数,让用户更新联系人的年龄。我想在评论区看看你想到了什么!
了解Redux中reducer所扮演的角色,应该能让你更好地理解引擎下面发生的事情。若是你有兴趣阅读更多关于在Redux中使用reducer的内容,能够查看官方文档。