同构(React / Redux / Express / Mongo)应用程序

时间:2016-04-15 08:30:24

标签: reactjs mongoose redux universal isomorphic-javascript

我最近使用React-Redux-Express-Mongoose堆栈构建了一些isomporphic / univeral项目。

在我的猫鼬模型中包含了很多商业逻辑。作为一个非常基本的例子(借口我的ES6):

import mongoose, {Schema} from 'mongoose';

const UserSchema = new Schema({
  name: String,
  password: String,
  role: String
});

UserSchema.methods.canDoSomeBusinessLogic = function(){
  return this.name === 'Jeff';
};

UserSchema.methods.isAdmin = function(){
  return this.role === 'admin';
};

这在服务器上都很棒,但是当这些模型在浏览器中作为普通的JSON对象进行水合时,我必须在一些React组件或Redux reducer中重新实现相同的业务逻辑,这不是我觉得很干净。我想知道如何最好地解决这个问题。

从浏览Mongoose,浏览器支持似乎有限,主要用于文档验证。我想我的主要选择是:

  • 将所有业务逻辑移动到某些" normal" JS类,并实例化那些地方。例如:

    # JS Class definition - classes/user.js
    export default class User {
        constructor(data = {}){
          Object.assign(this,data);
        }
    
        canDoSomeBusinessLogic(){
          return this.name === 'Jeff';
        };
    
        isAdmin(){
          return this.role === 'admin';
        }
    }
    
    # Server - api/controllers/user.js
    import UserClass from 
    User.findById(1,function(err,user){
        let user = new UserClass(user.toJSON();
    });
    
    # Client - reducers/User.js
    export default function authReducer(state = null, action) {
      switch (action.type) {
        case GET_USER:
          return new UserClass(action.response.data);
      }
    }
    
    # Client - containers/Page.jsx
    import {connect} from 'react-redux';
    
    @connect(state => ({user: state.user}))
    export default class Page extends React.Component {
        render(){
          if(this.props.user.isAdmin()){ 
            // Some admin 
          } 
        }
    }
    
  • 将所有业务逻辑移动到一些静态帮助函数中。我不会再写出整个例子,但基本上是:

    # helpers/user.js
    export function isAdmin(user){
        return user.role === 'admin';
    }
    

我认为上述2之间的差异只是个人偏好。但有没有人对同构应用程序和数据建模有任何其他想法?或者看过任何解决这个问题的人的开源示例。

作为对上述内容的扩展,有关同构save()函数的内容,例如User.save()。因此,如果在客户端上调用它,它可以对相关API端点执行POST,如果在服务器上运行,它将调用Mongoose save()函数。

1 个答案:

答案 0 :(得分:1)

剧透:期待一个自以为是的答复。没有权利'这样做的方法。

首先,我想明确difference between isomorphic and universal,以便您确切知道我们在说什么:

  

同构是在客户端和服务器端呈现之间无缝切换而不会丢失状态的功能方面。 Universal是一个术语,用于强调特定的JavaScript代码能够在多个环境中运行的事实。

是否值得将其抽象为通用应用程序?

一般来说,您想要的通用应用程序是让客户端和预呈现应用程序的服务器都加载相同的代码。虽然您可以从预先呈现应用程序的同一服务器上运行API,但我宁愿代理它并在不同的进程中运行它。

让我向您展示两个不同的React存储库:

Erikras着名的样板使用他的通用应用程序全局共享依赖关系,并在预呈现页面的服务器和客户端之间进行编码。虽然他可以,但他没有分享验证。 Survey API validation Survey client validation

Wellyshen没有API,但他也分享了他的依赖关系和代码,尽管只在服务器和客户端之间。 server加载路由,商店以及客户端应用程序正在运行的所有内容。那就是提供同构。

话虽如此,是否要在一个地方移动所有验证由您决定。我可能只会考虑复杂的验证案例,比如电子邮件验证,你实际上可以帮助它。 (这只是一个例子,对于电子邮件验证,您已经拥有validator)。在某些情况下,依靠API验证可能更方便,尽管不是最佳实践。

简单的验证,就像你的例子中那样,无论如何都可以毫不费力地完成redux-form,我知道没有直接的方法可以在API上进行翻译。相反,你可能应该在其上寻找express-validator

还有一件事,尽管一些非常受欢迎的React样板器将API和客户端放在一起,我倾向于使用两个不同的存储库:React +服务器端渲染和API。从长远来看,它将产生一个更清晰的代码,它将完全独立于另一个代码。 organizing-large-react-applications