React同构从0到1

前言

如果你想快速做react同构的新项目建议你去了解next.js等成熟框架,本教程仅限于想了解如何从0开始实现一个同构环境过程的同学,对于想改造现有spa项目的同学也很有帮助,具有一定参考价值。

需要实现的目标

  • 服务端渲染
  • 带路由的服务端渲染
  • 同构
  • 热更新
  • 前后端按需加载
  • 服务端预加载数据
  • css模块化(选修)
  • seo(选修)

以上任务中热更新和代码按需加载比较难实现,实现按需加载时会带来同构不一致的问题,随着你可能想做的越来越完美,就要添加功能,我们最起码的需求是要保证同构,否则这一切除了浪费服务器资源之外将毫无意义。

可能用到的技术

我们拥抱最新技术,所用框架全是最新版本,可能你看到这个教程时已经有更新的版本产生了。

  • webpack
  • express
  • react
  • react-dom
  • react-router-dom
  • react-router-config
  • react-loadable
  • redux
  • babel

看到这些框架是不是很凌乱,我做这个教程的时候仅仅对react和redux了解的还算熟悉,react-router-dom了解一般,仅仅会使用路由,其他的基本上是小白,用到啥就去github上看api即可,所以大家不必担心,而且这些不是必须的,比如express完全可以用koa取代,除了react技术栈其他的并不是核心,对于webpack建议大家多接触些,非常有用,它的生态已经很全面了,我是在做这个同构时对webpack有不少需求然后边做边学,现在想想它确实是个好帮手。

服务端渲染

该目标简单到爆,寥寥几行代码即可实现。

import React from 'react';
import { renderToString } from 'react-dom/server';
import express from 'express'; var app = express();
var ReactApp = (props) => <h1>Hello SSR from {props.path}</h1>; app.get('*', (req, res, next) => {
var ssrDomStr = renderToString(
<ReactApp path={req.url} />
); res.send(ssrDomStr);
return;
}); app.listen(3000);

注意,我用的是ES6语法,需要自行配置babel,用babel-node替代node运行程序即可。

带路由的服务端渲染

该实现目标也不难,原理很简单,就是客户端怎么搞服务端也怎么搞就是了,代码如下

import React from 'react';
import { StaticRouter, Switch, Route } from 'react-router-dom';
import { renderToString } from 'react-dom/server';
import express from 'express'; var app = express();
var Home = ({match}) => <h1>Hello Home, {match.url}</h1>;
var Todo = ({match}) => <h1>Hello Todo, {match.url}</h1>;
var ReactApp = (props) => (
<div>
<div>这里可以放些公共头之类的</div>
<Switch>
<Route path="/" exact component={Home}></Route>
<Route path="/todo" exact component={Todo}></Route>
</Switch>
</div>
); app.get('*', function (req, res, next) {
var context = {};
var ssrDomStr = renderToString(
<StaticRouter
location={req.url}
context={context}
>
<ReactApp />
</StaticRouter>
); res.send(ssrDomStr);
return;
}); app.listen(3000);

做到这里我们已经能让服务器根据输入的地址不同用react框架渲染出不同的内容了,为自己鼓个掌吧,简单分析下代码,上半部分就是很普通的react路由配置,下面处理渲染时使用了StaticRouter,这是专门在没有浏览器对象环境中使用的,比如服务端或者无头浏览器,我们传入当前路径给让StaticRouter知道匹配哪个路由,context属性能携带一些信息出来,比如有没有匹配到等,现在用不到这些信息,所以没做什么处理,后面随着深入可以慢慢了解。

同构

我们目前说的都是服务端渲染,既然同构至少要两端吧,不然谁和谁同,这里要说的就是客户端渲染和服务端渲染相同,你可能发现我们上面的代码返回的只是一些html片段,你里面如果绑定事件肯定不会在浏览器里实现,因为查看源码你会发现里面并没有脚本文件,因为客户端没有参与渲染(这里指客户端脚本没有参与渲染),而做这些需要同构。简单的说就是服务端和客户端协同渲染,准确来讲客户端接着服务渲染的结果继续渲染,所以这里一定要保证前后端对相同组件渲染出一致的结果,顾名思义叫同构,这只是我个人理解,也就是服务端分担了一部分客户端的工作,服务端分担要有条件的,就是它的渲染要和客户端一致,打个比方,你生产宝马汽车,从头到尾都是你生产,后来有个合作伙伴,他能生产宝马轮子,你可以让他生产轮子你接着轮子继续制造汽车,他能分担你工作唯一的条件就是他生产的轮子和你的轮子一模一样,否则他的轮子不管是大还是小都无法一次性组装一辆车,这种情况下你可能要对他的轮子修改,而此时正是浏览器会都抖动的原因,它在修改与服务端不一致的结果,我们在做的时候会踩到这些坑,庆幸的是react框架给做好了警告,我们很容易发现问题。说到这里,同构带的优势就很明显了,首屏无白屏现象,展示更快,至于为什么,想必大家明白了吧。废话少说,我们在服务端渲染的基础上加客户端渲染,所谓客户端渲染就是最熟悉不过的spa项目。这里会有一些坑或者叫一些难点(大神直接无视)。

// 核心代码同上, 在服务端返回给浏览器时需要带上webpack前端打包后的js文件,这里有整个前端的代码逻辑,包括事件绑定,样式加载(未抽离css文件时)等
res.send(html.repalce('<div id="root"></div>', `<div id="root">${ssrDomStr}</div>`));

上述中的html指的是html-webpack-plugin生成后的html,里面已经有客户端所需的入口代码,在它会接替服务渲染之后的事情,比如事件绑定,路由跳转等。整个代码篇幅较大,需要有相应的webpack配置,server等,这里不一一贴出代码,感谢的同学可以下载项目源码进行研究。

更完整版本请参考完整例子仓库地址。

(以后有时间再补全详细说明,现在感兴趣的同学可参考代码进行理解。)

React同构起步的更多相关文章

  1. React同构直出原理浅析

    通常,当客户端请求一个包含React组件页面的时候,服务端首先响应输出这个页面,客户端和服务端有了第一次交互.然后,如果加载组件的过程需要向服务端发出Ajax请求等,客户端和服务端又进行了一次交互,这 ...

  2. React 同构

    React 同构 搬运 https://segmentfault.com/a/1190000004671209 究竟什么是同构呢? 同构就是希望前端 后端都使用同一套逻辑 同一套代码 Nodejs出现 ...

  3. 打造高可靠与高性能的React同构解决方案

    前言 随着React的兴起, 结合Node直出的性能优势和React的组件化,React同构已然成为趋势之一.享受技术福利的同时,直面技术挑战,在复杂场景下,挑战10倍以上极致的性能优化. 什么是同构 ...

  4. React同构直出优化总结

    收录待用,修改转载已取得腾讯云授权 作者:郭林烁 joeyguo 原文地址 React 的实践从去年在 PC QQ家校群开始,由于 PC 上的网络及环境都相当好,所以在使用时可谓一帆风顺,偶尔遇到点小 ...

  5. React 同构开发(二)

    React 同构 所谓同构,简单的说就是客户端的代码可以在服务端运行,好处就是能极大的提升首屏时间,避免白屏,另外同构也给SEO提供了很多便利. React 同构得益于 React 的虚拟 DOM.虚 ...

  6. React 同构开发(一)

    为什么要做同构 要回答这个问题,首先要问什么是同构.所谓同构,顾名思义就是同一套代码,既可以运行在客户端(浏览器),又可以运行在服务器端(node). 我们知道,在前端的开发过程中,我们一般都会有一个 ...

  7. 自制的React同构脚手架

    代码地址如下:http://www.demodashi.com/demo/12575.html Web前端世界日新月异变化太快,为了让自己跟上节奏不掉队,总结出了自己的一套React脚手架,方便日后新 ...

  8. 腾讯新闻构建高性能的 react 同构直出方案

    在腾讯新闻抢金达人活动 node 同构直出渲染方案的总结文章中我们整体了解了下同构直出渲染方案在我们项目中的使用.正如我在上篇文章结尾所说的: 应用型技术的难点不是在克服技术问题,而是在于能够不断的结 ...

  9. 七天接手react项目-起步

    七天接手react项目-起步 背景 假如七天后必须接手一个 react 项目(spug - 一个开源运维平台),而笔者只会 vue,之前没有接触过 react,此刻能做的就是立刻展开一个"7 ...

随机推荐

  1. 数组遍历 forEach 方法

    数组的遍历 遍历数组,将数组中的所有元素都取出来. 使用for 循环执行数组的索引(length-1)相同的次数. var arr=["1", "5", &qu ...

  2. CSS currentColor 变量

    ㈠currentColor定义及理解 来自MDN的解释:currentColor代表了当前元素被应用上的color颜色值. 使用它可以将当前这个颜色值应用到其他属性上,或者嵌套元素的其他属性上. 你这 ...

  3. php上传大文件1G

    前段时间做视频上传业务,通过网页上传视频到服务器. 视频大小 小则几十M,大则 1G+,以一般的HTTP请求发送数据的方式的话,会遇到的问题:1,文件过大,超出服务端的请求大小限制:2,请求时间过长, ...

  4. JavaWeb_(SSH论坛)_五、帖子模块

    基于SSH框架的小型论坛项目 一.项目入门 传送门 二.框架整合 传送门 三.用户模块 传送门 四.页面显示 传送门 五.帖子模块 传送门 六.点赞模块 传送门 七.辅助模块 传送门 回复帖子 分析回 ...

  5. git梳理

    http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000 本地库管理命令 git init ...

  6. 如何快速查询中科院JCR分区和汤森路透JCR分区

    参考: https://blog.csdn.net/chichuhe/article/details/83054624 https://blog.csdn.net/Sunflower02/articl ...

  7. JavaWeb--Servlet 详解

    一.基本概念 Servlet是运行在Web服务器上的小程序,通过http协议和客户端进行交互.这里的客户端一般为浏览器,发送http请求(request)给服务器(如Tomcat).服务器接收到请求后 ...

  8. 作业要求20191010-9 alpha week 1/2 Scrum立会报告+燃尽图 07

    此作业要求参见:https://edu.cnblogs.com/campus/nenu/2019fall/homework/8752 一.小组情况组长:贺敬文组员:彭思雨 王志文 位军营 杨萍队名:胜 ...

  9. Alpha发布--美工+文案

    此作业对应要求参见:https://edu.cnblogs.com/campus/nenu/2019fall/homework/8677 一.美工: 1.产品logo 2.原型页面展示 2.1 进入萌 ...

  10. 让Socket穿透Windows防火墙

    原文地址:https://blog.csdn.net/zuishikonghuan/article/details/48030539 创建了ServerSocket以后,并不是没事了,其实上,为了系统 ...