在redux初始状态和reducers中使用嵌套对象

时间:2017-11-15 09:30:12

标签: reactjs redux react-redux react-router-v4

我的仪表板有一个由react-router分隔的部分。

部分是:

  • 分类

  • 考试

  • 报告

让我们来看看考试部分。我们将这种状态作为初始状态。

{
        ID: null,          
        RandomizeQuestions: false,
        RandomizeAnswers: false,
        Pages: [
            {
                ID: 1,
                Title: 'Page one',                
                Blocks: [
                    {
                        ID: 1,
                        Title: 'Block One',                           
                        Questions: [
                            {
                                ID: 1,                                   
                                Title: "Quesiton title is here",
                                Answers: [
                                    {
                                        ID: 1,
                                        Title: "Answer 1"
                                    },
                                    {
                                        ID: 2,
                                        Title: "Answer 2"
                                    }
                                ]
                            }
                        ]
                    }
                ]
            }
        ]
    }

我知道当我使用redux时,状态应该变平并标准化。但那是我的确切问题。如果我试图规范我的状态,它应该是这样的:

{
Exam: {
    ID: null,       
    RandomizeQuestions: false,
    RandomizeAnswers: false
},
ExamPages: [
    {
        ExamId: 1,
        ID: 1,
        Title: 'Page One'           
    }
],
ExamBlocks: [
    {
        ID: 1,
        Title: 'The New Block',            
        Questions: []
    }
],
ExamQuestions: [],
ExamAnswers: []
}

让我们假设它没关系,我也不会有问题。但是当发生在其他部分?

类别也有自己的状态也很大并且报告也是如此。 (还有其他部分我没有提到)

然后我的combineReducer看起来像这样:

import {combineReducers} from 'redux'
import Exam from './redc.exams.jsx'
import ExamBlocks from './redc.blocks.jsx'

const rootReducer = combineReducers({
    Exam,
    ExamBlocks
})

export default rootReducer

当然我应该为该对象中的每个数组都有一个reducer。

所以我的主要问题是我怎么能有这种结构:

const initialState = {
    Exams: {
        Blocks: [],
        Questions: [],
        Answers: []
    },
    Categories: {
        Menus: [],
        Users: []
    },
    Report: {
        MainReports: [],
        SideReports: []
    }
}

请记住,我希望每个都有单独的减速器。 块的减速器,问题的减速器等......

更新#1

我试过@Tom Fenech在答案中说但是在最终的combineReducers之前无法组合减速器。 现在我的root reducers看起来像这样:

import {combineReducers} from 'redux'

//Exams
import Exams from './ExamsReducers/redc.exams.jsx'
import Blocks from './ExamsReducers/redc.blocks.jsx'

//Categories
import Categories from './CategoriesReducers/redc.categories.jsx'

const rootReducer = combineReducers({
        Exams,
        Categories,
        Blocks,
})

export default rootReducer

我尝试了他所说的内容,这是我改变后的代码:

import {combineReducers} from 'redux'

//Exams
import Exams from './ExamsReducers/redc.exams.jsx'
import Blocks from './ExamsReducers/redc.blocks.jsx'

//Categories
import Categories from './CategoriesReducers/redc.categories.jsx'

const examRedc = combineReducers(Exams,Blocks )
const catsRedc = combineReducers(Categories)

const rootReducer = combineReducers(examRedc, catsRedc)

export default rootReducer

我收到此错误:

Store does not have a valid reducer. Make sure the argument passed to combineReducers is an object whose values are reducers.

当我在其中一个组件中记录状态时

var mapDispatchToProps = function (dispatch) {
    return {
        AddBlock: function () {
            dispatch(addBlock());
        }
    }
};

const mapStateToProps = function (state) {
    console.log(state); //////HERE
    return {Blocks: state.Blocks};
}

export default connect(mapStateToProps, mapDispatchToProps)(Blocks)

我得到的这个状态最终不是我想要的。

final output

2 个答案:

答案 0 :(得分:2)

我认为Blocks内部不需要QuestionsAnswersExams。我会在顶层建议这样的事情:

{
    Exams: {
        [ID]: {
            ID: string,
            RandomizeQuestions: boolean,
            RandomizeAnswers: boolean,
            Blocks: string[] // array of block IDs
        }
    }
    Blocks: {
        [ID]: {
            ID: string, 
            Title: string,  
            Questions: string[] // array of question IDs
        }
    },
    Questions: // etc.
}

现在,我们不是存储嵌套对象,而是存储他们的ID以跟踪所有权。

此状态将使用:

创建
state = combineReducers({
    examsReducer, 
    blocksReducer,
    // ...more reducers
})

如果要将整体状态拆分为多个部分,可以使用以下内容:

const examStuff = combineReducers({
    examsReducer,
    blocksReducer,
    // ...
});

const categoryStuff = combineReducers({
    categoriesReducer,
    menusReducer,
    // ...
});

const state = combineReducers({
    examStuff,
    categoryStuff
});

然后状态是:

{
    examStuff: {} // the object defined at the top of question,
    categoryStuff: {},
    otherStuff: {}
}

答案 1 :(得分:1)

您可以使用嵌套的reducer结构,如

// block_reducer.js
export const reducer = (state = [], action) => {
   switch (action.type) {
   case BLOCK_ACTION:
     return [{a:1}, {b:2}]
 }
  return state
}


// exam_reducer.js
import {combineReducers} from 'redux'
import {reducer as BlockReducer} from './block_reducer'

export const reducer = combineReducers({
    Blocks: BlockReducer,
    Sections: .....,
    Answers: .......
})

// root_reducer.js
import {combineReducers} from 'redux'
import {reducer as examReducers} from './exam_reducers'

export const reducer = combineReducers({
    Exams: examReducers,
    Categories: .....,
    Report: ......
})