[英]State in redux/react app has a property with the name of the reducer
I am creating an app using Redux and React. 我正在使用Redux和React创建一个应用程序。 I run into a problem where I cannot map state to component properties since the state has a property that matches the name of the reducer I used. 我遇到一个问题,我无法将状态映射到组件属性,因为状态具有与我使用的reducer的名称匹配的属性。
The root reducer is created with combineReducers
method root reducer是使用combineReducers
方法创建的
const rootReducer = combineReducers({
appReducer
});
The initial state is 最初的状态是
const initialState = {
sources: [],
left: {},
right: {},
diff: {}
}
However in the component function mapStateToProps
: 但是在组件函数mapStateToProps
:
function mapStateToProps(state) {
return {
sources: state.sources
}
}
The state.sources
is undefined
because the value of state
parameter is state.sources
是undefined
因为state
参数的值是
{
appReducer: {
sources: [],
left: {},
right: {},
diff: {}
}
}
Is this a feature of redux? 这是redux的一个特性吗? So when I use more reducers, all of them will add new property to state
variable? 所以当我使用更多reducers时,所有这些都会为state
变量添加新属性? Or is there something wrong on my side (I never noticed this behavior in redux tutorials). 或者我身边有什么问题(我在redux教程中从未注意到这种行为)。
Thanks 谢谢
If you only have a single reducer, you don't need combineReducers()
. 如果您只有一个reducer,则不需要combineReducers()
。 Just use it directly: 直接使用它:
const initialState = {
sources: [],
left: {},
right: {}
}
function app(state = initialState, action) {
switch (action.type) {
case 'ADD_SOURCE':
return Object.assign({}, state, {
sources: [...state.sources, action.newSource]
})
case 'ADD_SOURCE_TO_LEFT':
return Object.assign({}, state, {
left: Object.assign({}, state.left, {
[action.sourceId]: true
})
})
case 'ADD_SOURCE_TO_RIGHT':
return Object.assign({}, state, {
right: Object.assign({}, state.right, {
[action.sourceId]: true
})
})
default:
return state
}
}
Now you can create a store with that reducer: 现在您可以使用该reducer创建一个商店:
import { createStore } from 'redux'
const store = createStore(app)
And connect a component to it: 并将组件连接到它:
const mapStateToProps = (state) => ({
sources: state.sources
})
However your reducer is hard to read because it update many different things at once. 但是你的reducer很难阅读,因为它会同时更新许多不同的东西。 Now, this is the moment you want to split it into several independent reducers: 现在, 这是您想要将其拆分为多个独立Reducer的时刻:
function sources(state = [], action) {
switch (action.type) {
case 'ADD_SOURCE':
return [...state.sources, action.newSource]
default:
return state
}
}
function left(state = {}, action) {
switch (action.type) {
case 'ADD_SOURCE_TO_LEFT':
return Object.assign({}, state, {
[action.sourceId]: true
})
default:
return state
}
}
function right(state = {}, action) {
switch (action.type) {
case 'ADD_SOURCE_TO_RIGHT':
return Object.assign({}, state, {
[action.sourceId]: true
})
default:
return state
}
}
function app(state = {}, action) {
return {
sources: sources(state.sources, action),
left: left(state.left, action),
right: right(state.right, action),
}
}
This is easier to maintain and understand, and it also makes it easier to change and test reducers independently. 这更易于维护和理解,并且还可以更轻松地独立更改和测试减速器。
Finally, as the last step, we can use combineReducers()
to generate the root app
reducer instead of writing it by hand: 最后,作为最后一步,我们可以使用combineReducers()
来生成root app
reducer而不是手动编写它:
// function app(state = {}, action) {
// return {
// sources: sources(state.sources, action),
// left: left(state.left, action),
// right: right(state.right, action),
// }
// }
import { combineReducers } from 'redux'
const app = combineReducers({
sources,
left,
right
})
There is no large benefit to using combineReducers()
instead of writing the root reducer by hand except that it's slightly more efficient and will likely save you a few typos. 使用combineReducers()
而不是手动编写根减速器没有什么大的好处,除了它稍微更高效并且可能会省去一些拼写错误。 Also, you can apply this pattern more than once in your app: it's fine to combine unrelated reducers into a single reducer several times in a nested way. 此外,您可以在应用程序中多次应用此模式:将不相关的Reducer以嵌套方式多次组合到单个reducer中可以。
All this refactoring would have no effect on the components. 所有这些重构都不会对组件产生影响。
I would suggest you to watch my free Egghead course on Redux which covers this pattern of reducer composition and shows how combineReducers()
is implemented. 我建议你在Redux上观看我的免费Egghead课程,该课程涵盖了这种减速器组成模式,并展示了如何实现combineReducers()
。
Actually, I believe your initial state would be: 实际上,我相信你的初始状态是:
{
appReducer: {
sources: [],
left: {},
right: {},
diff: {}
}
}
This is because combineReducers
works by taking the name of the reducer, and mapping its contents to that name. 这是因为combineReducers
通过获取reducer的名称并将其内容映射到该名称来工作。
Also, just a note, but if you're going to use more than 1 reducer, the names of your reducers should be more specific than appReducer
, and (just my personal opinion) they don't need the word reducer
. 另外,只是一个注释,但如果你要使用超过1个减速器,你的减速器的名称应该比appReducer
更具体,并且(仅我的个人意见)他们不需要reducer
这个词。 A typical app might look like this: 典型的应用程序可能如下所示:
combineReducers({
user: userReducer,
messages: messagesReducer,
notifications: notificationsReducer
});
Then, your state could be accessed like: 然后,可以访问您的州:
state.user.email
state.messages[0]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.