代码之家  ›  专栏  ›  技术社区  ›  AndrewMcLagan

重做:组织容器、组件、动作和减速器

  •  6
  • AndrewMcLagan  · 技术社区  · 8 年前

    问题是:

    在大型容器、组件、动作和减速器的组织中,最容易维护和推荐的最佳实践是什么 React/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
    

    这很管用!虽然这个设计似乎有几个问题。

    问题:

    当我们需要访问 actions , selectors sagas 从另一个容器来看,它似乎是反模式的。假设我们有一个全球 /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 来自 /应用程序 我们内部的集装箱 /BookList 我们需要在其中重新创建它的容器 /BookList/selectors.js (肯定错了吗?)或从导入 /App/selectors (它是否总是完全相同的选择器…?否)。这两个appraoches对我来说都是次优的。

    这个用例的主要示例是身份验证(啊…auth,我们很喜欢恨你),因为它是一个 非常 常见的“副作用”模型。我们经常需要访问 /Auth /PasswordRecover , /PasswordReset , /Login , /Signup /授权 contianer根本没有实际的组件!

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

    只包含上面提到的各种且通常不相关的身份验证容器的所有Redux辅助对象。

    1 回复  |  直到 8 年前
        1
  •  5
  •   Pierre Criulanscy    8 年前

    我个人使用 ducks-modular-redux 提议

    这不是“官方”推荐的方法,但对我来说效果很好。每个“鸭子”都包含一个 actionTypes.js , actionCreators.js , reducers.js , sagas.js selectors.js 文件夹。这些文件中没有对其他鸭子的依赖关系,以避免循环依赖或 duck circle ,每个“鸭子”只包含它必须管理的逻辑。

    然后,从根本上我有一个 components 和a containers 文件夹和一些根文件:

    components/

    containers/ 文件夹包含从上面的纯组件创建的容器。当容器需要特定 selector 涉及许多“鸭子”,我把它写在我写的同一个文件中 <Container/> 组件,因为它与此特定容器相关。如果 选择器 是共享的accros多个容器,我在一个单独的文件中(或在提供这些道具的HoC中)创建它。

    rootReducers.js :通过组合所有减速器,简单地暴露根减速器

    rootSelectors.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
    

    它让我们可以“隐藏”每只鸭子内部的状态形状 选择器.js 文件自每个 选择器 rootSelector 在您的 selector.js 文件夹。

    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.js 或a ducks/Taxonomies.js 包含所有这5个文件的文件( actionTypes.js , actionCreator s.js软件 , 减速器.js , 选择器.js , 传奇.js )合并在一起。