rails-webpack-react-flux, 在 Rails/Webpack/React/Flux的服务器端渲染中,示例CRUD应用程序

分享于 

9分钟阅读

GitHub

  繁體 雙語
A Sample CRUD app in Rails/Webpack/React/Flux with server side rendering
  • 源代码名称:rails-webpack-react-flux
  • 源代码网址:http://www.github.com/nambrot/rails-webpack-react-flux
  • rails-webpack-react-flux源代码文档
  • rails-webpack-react-flux源代码下载
  • Git URL:
    git://www.github.com/nambrot/rails-webpack-react-flux.git
    Git Clone代码到本地:
    git clone http://www.github.com/nambrot/rails-webpack-react-flux
    Subversion代码到本地:
    $ svn co --depth empty http://www.github.com/nambrot/rails-webpack-react-flux
    Checked out revision 1.
    $ cd repo
    $ svn up trunk
    
    如何使用 Rails。web-service。React和流量构建服务器渲染web应用程序

    阅读我的网站上的完整博客文章,并在http://rails-react.nambrot.com/网站上演示。

    我已经建立了一个非常简单的博客,提供以下功能:

    • 完全服务器呈现的HTML,意味着你实际上可以在没有启用JS的情况下使用应用程序。
    • 最小化不必要的数据获取,如embededing中的相关数据中的相关数据,如果需要则加载附加数据
    • 加载后,所有转发都是客户端呈现和缓存的,从而使它的响应。

    我使用 Rails 作为我最喜欢的web框架,并通过on将它的与客户端的React和流量结合在一起。 i credits,credits,credits,,,,credits,credits,credits,credits,。

    大多数 Rails/React/Flux 示例通常缺少两个部门:

    • 它们是"只是只是"todomvc,换句话说,不关心自己使用localstorage持久化到一个真正的服务器。
    • 带React的rpc示例通常只关注于在不解决数据管理策略的情况下输出 HTML。 大多数将返回 HTML,但需要第二个rountrip来初始化。 当它们完成时,它们通常会加载整个 Collection,这不是那么好。

    我将尽可以能简洁地将这一点保持在我如何接近主题的步骤中。 我从一个非常基本的Rails 博客开始,我们将逐步进行"神圣 grailify"。 下面的链接将所有指向希望提交的提交消息的。

    1.介绍 web pack和 NPM。

    很喜欢资产管道,但是缺少 true 模块显然可以得到大量客户端代码。 在 using Webpack中,我们将使用 web pack 编写模块化代码,并使用大量的NPM生态系统,以及客户端资产的简单编译和热加载系统。

    2设置基本响应和流量

    我们将在不考虑服务器部分的情况下设置通道架构的范围,现在我们只需要获取所有内容。 包括设置基本应用结构

    React路由器

    
    
    
    
    # app.js
    
    
    routes = (
    
    
     <Route name="app" path="/">
    
    
     <Route name="posts">
    
    
     <Route name="post" path=":postId">
    
    
     <DefaultRoute handler={PostShow}/>
    
    
     </Route>
    
    
     <DefaultRoute handler={PostsIndex}/>
    
    
     </Route>
    
    
     <DefaultRoute handler={PostsIndex}/>
    
    
     </Route>
    
    
    )
    
    
    
    

    带 Flummox的 流量

    • 组件
    
    
    
    
    # components/posts/index.cjsx
    
    
    Index = React.createClass
    
    
     displayName: "PostsIndex"
    
    
     render: ->
    
    
     <div>
    
    
     {
    
    
     @props.posts.map (post) ->
    
    
     <article key={post.get('id')}>
    
    
     <header>
    
    
     <h3>{post.get('title')}</h3>
    
    
     </header>
    
    
     </article>
    
    
    . toArray()
    
    
     }
    
    
     </div>
    
    
    
    FluxIndex = React.createClass
    
    
     displayName: "WrappedPostsIndex"
    
    
     render: ->
    
    
     <FluxComponent connectToStores={
    
    
     posts: (store) => posts: store.getAllPosts(), didFetchAll: store.didFetchAll()
    
    
     }>
    
    
     <Index />
    
    
     </FluxComponent>
    
    
    
    
    • 操作
    
    
    
    
    # actions/post.coffee
    
    
    class PostActions extends Actions
    
    
     fetchAllPosts: ->
    
    
     axios.get('/posts', headers: acceptJSON)
    
    
    . then (posts) -> posts.data
    
    
     fetchPost: (id) ->
    
    
     axios.get("/posts/#{id}", headers: acceptJSON)
    
    
    . then (response) -> response.data
    
    
    
     createPost: (post) ->
    
    
     axios.post('/posts.json', post: post, headers: acceptJSON)
    
    
    . then (response) -> response.data
    
    
     updatePost: (post) ->
    
    
     axios.put("/posts/#{post.id}", post: post, headers:acceptJSON)
    
    
    . then (response) -> response.data
    
    
    
    
    • 商店
    
    
    
    
    # stores/post.coffee
    
    
    class PostsStore extends Store
    
    
     constructor: (flux) ->
    
    
     super()
    
    
    
     postActionIds = flux.getActionIds('posts')
    
    
     @registerAsync postActionIds.fetchAllPosts, @startFetchingPosts, @fetchedAllPosts
    
    
     @registerAsync postActionIds.fetchPost, @startFetchingPost, @fetchedPost
    
    
     @registerAsync postActionIds.createPost, @startCreatePost, @createdPost
    
    
     @registerAsync postActionIds.updatePost, @startUpdatingPost, @updatedPost
    
    
    
     @state = getDefaultState()
    
    
     @flux = flux
    
    
    
    

    3。存储反序列化代码

    服务器端呈现的第一步是能够将数据反序列化到客户端的存储中。 这也避免了对数据的双向请求。 React也很聪明,因为结果HTML是相同的,不能触摸 DOM。

    
    
    
    
    # app.js
    
    
    flux = new Flux()
    
    
    flux.deserialize(window.serializedStoreState) if window.serializedStoreState
    
    
    Router.run routes, Router.HistoryLocation, (Handler, state) ->
    
    
     handler = <FluxComponent flux={flux} render={ => <Handler />}></FluxComponent>
    
    
     React.render(handler, document.getElementById("main"))
    
    
    
    
    
    
    
    
    # stores/post.coffee
    
    
    class PostsStore extends Store
    
    
     @deserialize: (serializedState) ->
    
    
     if serializedState
    
    
     posts: getPostsFromJSON(JSON.parse(serializedState.serializedPosts))
    
    
     didFetchAll: serializedState.didFetchAll
    
    
     else
    
    
     getDefaultState()
    
    
    
    

    4添加服务器端渲染

    我们将使用一个简单的express服务器,它将采用 1. 路由和 2.serializedState作为参数,只是返回HTML地址。 结果是返回了完整的HTML页面。 实际上,你现在应该能够在不需要Javascript的情况下导航页面,time-to-render上的更快,显著的优势。 缺点是"往返行程"到express服务器

    
    
    
    
    # server.coffee
    
    
    renderToString = (route, serializedStoreState, callback) ->
    
    
     flux = new Flux()
    
    
     flux.deserialize(serializedStoreState)
    
    
    
     Router.run routes, route, (Handler, state) ->
    
    
     html = React.renderToString(<FluxComponent flux={flux} render={ => <Handler />}></FluxComponent>)
    
    
     embeddedStoreState = "<script>"
    
    
     embeddedStoreState += "window.serializedStoreState = " + JSON.stringify(serializedStoreState)
    
    
     embeddedStoreState += "</script>"
    
    
     callback (html + embeddedStoreState)
    
    
    
    
    
    
    
    
    # app/helpers/react_helper.rb
    
    
    module ReactHelper
    
    
     def renderSerializedStoreState(state)
    
    
     component = HTTParty.post "http://localhost:3001", body: {path: request.path, serializedStoreState: state.to_json}.to_json, headers: {'Content-Type' => "application/json"}
    
    
     component.html_safe
    
    
     end
    
    
    end
    
    
    
    

    结论

    正如你所看到的,构建"右边"web应用程序并不简单,仍然有很多决策和配置。 虽然好处很大,但对于许多应用来说,成本可能不是合理的,并且应该通过 上面 交易offs谨慎考虑。 我对一个子的FastBoot感兴趣,这似乎是获得好处的最少工作量。


    Server  rails  sam  SID  服务器端  CRUD  
    相关文章