2016-02-27 69 views
7

我正在使用Redux和React创建应用程序。我遇到了一个问题,我无法将状态映射到组件属性,因为状态的属性与我使用的reducer的名称相匹配。状态在redux/react应用程序中有一个属性,名称为reducer

的降低与combineReducers方法创建

const rootReducer = combineReducers({ 
    appReducer 
}) 

初始状态是

const initialState = { 
    sources: [], 
    left: {}, 
    right: {}, 
    diff: {} 
} 

然而在组件功能mapStateToProps

function mapStateToProps(state) { 
    return { 
    sources: state.sources 
    } 
} 

state.sourcesundefined因为该值state参数是

{ 
    appReducer: { 
    sources: [], 
    left: {}, 
    right: {}, 
    diff: {} 
    } 
} 

这是redux的一项功能吗?所以当我使用更多的减速器时,他们都会将新的属性添加到state变量中?或者在我身边有什么不对(我从来没有注意到这个在redux教程中的行为)。

感谢

+1

你的代码是正确的'state.appReducer。来源'你需要减速器名 –

+3

想象一下,你有2,3减速器每个减速器有'源'属性 –

+1

你可以通过state.appReducer获得特定的'sources'。 sources'和'state.appReducer.2来源' –

回答

17

如果你只有一个单一的减速,你不需要combineReducers()

combineReducers({ 
    user: userReducer, 
    messages: messagesReducer, 
    notifications: notificationsReducer 
}); 

然后,你的国家可以像访问。只需直接使用它:

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 
    } 
} 

现在可以创建与减速商店:

import { createStore } from 'redux' 
const store = createStore(app) 

和部件连接到它:

const mapStateToProps = (state) => ({ 
    sources: state.sources 
}) 

但是你减速是难以阅读因为它一次更新许多不同的东西。现在,这你想将它分割成几个独立的减速的时刻:

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), 
    } 
} 

这是更容易维护和理解,这也使得它更容易独立地改变和测试减速。

最后,作为最后一步,我们可以使用combineReducers()产生的根源app减速而不是通过手工编写它的:

// 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 
}) 

没有大的好处是用combineReducers(),而不是通过编写根减速除了它稍微更有效率,并且可能会为您节省几个拼写错误。另外,您可以在应用程序中多次应用此模式:将无关的减速器以嵌套方式组合到单个缩减器中可以多次应用此模式。

所有这些重构对组件都没有影响。

我建议你看我的free Egghead course on Redux,它涵盖了减速机组合的这种模式,并显示了如何实现combineReducers()

+0

感谢丹的解释和链接到这些视频 –

+0

我总是喜欢你的解释,简单和准确。 –

5

其实,我相信你的初始状态是:

{ 
    appReducer: { 
    sources: [], 
    left: {}, 
    right: {}, 
    diff: {} 
    } 
} 

这是因为combineReducers作品采取减速机的名称,其内容映射到该名称。

此外,只是一个说明,但如果你打算使用多个减速器,你的减速器的名称应该比appReducer更具体,而且(就我个人看来)他们不需要这个词reducer 。一个典型的应用可能是这样的:

state.user.email 
state.messages[0] 
+0

你说得对,我应该改变'initialState'对象是相应的吗? –

+1

这个想法是reducer的每个分支都负责它自己的'initialState'。你的根reducer应该没有initialState,并且每个reducer都应该只包含它的东西,所以你的'appReducer'会是一个对象,来源,左,右等 –

相关问题