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

Using nested objects in redux initial state and reducers

我的仪表板有一个由 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的时候应该把state扁平化归一化。但那是我的确切问题。如果我尝试使我的状态正常化,它应该是这样的:

{
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: []
    }
}

请记住,我想为它们中的每一个都设置单独的减速器。 Blocks 的 reducer,Questions 的 reducer 等等...

更新 #1

我试过 @Tom Fenech 在答案中说的但不能在最终的 combineReducers 之前组合 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)

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

你可以有像

这样的嵌套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: ......
})

我认为 Exams 中不需要 BlocksQuestionsAnswers。我会在顶层提出这样的建议:

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