2016-07-14 59 views
6

问题:终极版:组织容器,组件,动作和减速

什么是组织在一个大 React/Redux应用程序容器,组件,动作和减速的最易维护和建议的最佳实践?

我的看法:

目前的趋势似乎组织Redux的抵押品(动作,减速机,传奇......)围绕有关的容器组件。例如

/src 
    /components 
     /... 
    /contianers 
     /BookList 
      actions.js 
      constants.js 
      reducer.js 
      selectors.js 
      sagas.js 
      index.js 
     /BookSingle 
      actions.js 
      constants.js 
      reducer.js 
      selectors.js 
      sagas.js 
      index.js   
    app.js 
    routes.js 

This works great!虽然这种设计似乎有几个问题。

的问题:

当我们需要从它似乎是一个反模式的另一个容器访问actionsselectorssagas。比方说,我们有一个全球性的/App容器,其中有一个reducer/state,用于存储我们在整个应用程序中使用的信息,例如类别和枚举类型。从示例如下上面,有一个状态树:

{ 
    app: { 
     taxonomies: { 
      genres: [genre, genre, genre], 
      year: [year, year, year], 
      subject: [subject,subject,subject], 
     } 
    } 
    books: { 
     entities: { 
      books: [book, book, book, book], 
      chapters: [chapter, chapter, chapter], 
      authors: [author,author,author], 
     } 
    }, 
    book: { 
     entities: { 
      book: book, 
      chapters: [chapter, chapter, chapter], 
      author: author, 
     } 
    }, 
} 

如果我们要使用selector/App容器我们/BookList容器,我们需要可以重新创建它在/BookList/selectors.js内(当然错了吗?)或导入它从/App/selectors(它会永远是相同的选择器..?否)。这两种说法对我来说都不是最理想的。

这个用例的主要例子是身份验证(ah ... auth,我们喜欢讨厌你),因为它是一个非常有效的常见的“副作用”模型。我们经常需要访问各种应用程序中的传奇故事,动作和选择器。我们可能有容器/PasswordRecover,/PasswordReset,/Login, /Signup ....实际上在我们的应用程序中我们的/Auth contianer根本没有实际的组件!

/src 
    /contianers 
     /Auth 
      actions.js 
      constants.js 
      reducer.js 
      selectors.js 
      sagas.js 

简单地包含上述各种通常不相关的身份验证容器的所有Redux资料。

+0

我很好奇,你现在的结构如何使用你的选择器?假设一个组件使用'BookList'选择器函数,你能告诉我你的'mapStateToProps'函数吗?你是否在传递'状态'?或'state.booklist' – xiaofan2406

回答

5

我个人使用ducks-modular-redux建议。

这不是“官方”推荐的方式,但它对我很好。每个“鸭”包含actionTypes.js,actionCreators.js,reducers.js,sagas.jsselectors.js文件。对这些文件中的其他鸭子没有依赖性以避免循环依赖或者duck circle,每个“duck”只包含它必须管理的逻辑。

然后,在根我有一个componentscontainers文件夹和一些根文件:

components/文件夹包含

containers/文件夹包含创建容器我的应用程序的所有纯组分纯粹的组件。当一个容器需要一个涉及许多“鸭子”的特定selector时,我将它写在我编写<Container/>组件的同一个文件中,因为它与此特定容器相关。如果selector共享accros多个容器,我创建它在一个单独的文件(或在提供这些道具的HoC)。

rootReducers.js

/* let's consider this state shape 

state = { 
    books: { 
     items: { // id ordered book items 
      ... 
     } 
    }, 
    taxonomies: { 
     items: { // id ordered taxonomy items 
      ... 
     } 
    } 
} 

*/ 
export const getBooksRoot = (state) => state.books 

export const getTaxonomiesRoot = (state) => state.taxonomies 
:只需在您的情况下将所有减速

rootSelectors.js暴露的状态的每片的根选择,例如,你可以有这样的事暴露了根减速

它让我们“隐藏”每个鸭子selectors.js文件中的状态形状。由于每个selector接收鸭子的整个状态,因此您只需在selector.js文件中输入相应的rootSelector即可。

rootSagas.js撰写的所有传奇的鸭子内管理涉及许多“鸭子”复杂流动。

所以你的情况,该结构可以是:

components/ 
containers/ 
ducks/ 
    Books/ 
     actionTypes.js 
     actionCreators.js 
     reducers.js 
     selectors.js 
     sagas.js 
    Taxonomies/ 
     actionTypes.js 
     actionCreators.js 
     reducers.js 
     selectors.js 
     sagas.js 
rootSelectors.js 
rootReducers.js 
rootSagas.js 

当我的“鸭子”足够小,我经常跳过该文件夹的创建和直接写ducks/Books.jsducks/Taxonomies.js文件,所有这5个文件(actionTypes.js,actionCreators.js, reducers.js,selectors.js,sagas.js)合并在一起。