小哥哥, React SSR 要不要了解下-实用篇

上一篇文章中咱们实现了一个简单的 hello world, 这一节咱们继续完善咱们的项目. 做为实用篇本篇将会添加 react-router reduxhtml

并经过 react-helmet 实现自定义的 meta 标签, 完善 SEO. 这个实在是不想写了. 下篇吧...前端

加入路由畅游皇冠赌场

客户端渲染配置 react-router

来到皇冠赌场的你们那确定是丈二的和尚, 摸不着头脑呀. 那么路由就应运而生了, 关于路由的原理建议你们看看这篇文章.node

9150e4e5gy1fznxtqxc8sg206y06yab7

若是你看了还回来了, 那说明仍是咱们澳门 XXXX 更加的有意思 😹.react

谈到赌场无非就是这老四样, 抓牌, 看牌, 洗牌, 码牌~ios

2019-07-16-17-28-14

那么咱们就开始, 建立几个页面. 页面的代码结构以下图所示.git

2019-07-16-17-30-43

为了便于各个 level 的小伙伴理解, 这里无耻的运用了拼音命名法. 代码改动在这里github

其次, 安装 react-router-dom 依赖, 并修改 App.jsx 和 client.js 文件, diff 在这里web

修改后的 App.jsx 文件面试

import React from 'react';
// 从 react-router-dom 引入基础组件
import { NavLink, Switch, Route } from 'react-router-dom';

// 引入皇冠赌场的页面
import Home from './Home.jsx';
import Zhuapai from './Zhuapai.jsx';
import Kanpai from './Kanpai.jsx';
import Xipai from './Xipai.jsx';
import Mapai from './Mapai.jsx';

export default class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  render() {
    return (
      <div className="ssr-show">
        <h1>欢迎来到澳门皇冠赌场</h1>

        <NavLink to="/">首页</NavLink>
        <NavLink to="/Zhuapai">抓牌</NavLink>
        <NavLink to="/Kanpai">看牌</NavLink>
        <NavLink to="/Xipai">洗牌</NavLink>
        <NavLink to="/Mapai">码牌</NavLink>

        <Switch>
          <Route path="/" component={Home} />
          <Route path="/Zhuapai" component={Zhuapai} />
          <Route path="/Kanpai" component={Kanpai} />
          <Route path="/Xipai" component={Xipai} />
          <Route path="/Mapai" component={Mapai} />
        </Switch>
      </div>
    );
  }
}
复制代码

修改后的 client.js 为ajax

import React from 'react';
import ReactDOM from 'react-dom';
// 从 react-router-dom 里边导入 BrowserRouter 组件
import { BrowserRouter } from 'react-router-dom';
import App from './components/App.jsx';

// 包装一下 App 组件
ReactDOM.render(
  <BrowserRouter> <App /> </BrowserRouter>,
  document.getElementById('app'),
);
复制代码

目前为止, 路由就算是配完了. 执行 npm run build:client 后, 用浏览器打开 index.html 文件.

2019-07-15-16-03-01

成功就在眼前, 可是不免有一点小小的障碍~

这个报错的大体意思就是, 本地的文件不能用 react-router, 那么咱们只能把它放到一个服务器上了. 仍是咱们的老伙伴 --- live-server 直接执行 live-server ./dist

浏览器打开 localhost:8080

react-router-err

咱们不难发现, 点击连接的时候浏览器地址栏有变化, 可是咱们并不能体验到从发牌到码牌的一条龙"服务"...

看了下 react-router 的 官方文档 原来咱们没有指定路径匹配必须得精准匹配. 那么咱们加上 exact 属性试试咧~

react-router

此时的代码 diff

到目前为止, 我咱们已经能够畅游澳门皇冠赌场了, 抓牌看牌洗牌码牌样样精通~

配置服务端渲染的 react-router

轻松搞定了客户端渲染的 react-router, 服务端渲染的话那就更加的简单了.

  • 首先确定是要引入 react-router-dom 依赖的(ps: ssr 须要导入的是 StaticRouter)
    2019-07-27-09-21-30
  • 建立路由上线文对象, 并获取到当前用户访问的路径 path
    2019-07-27-09-22-59
  • 最后, 利用第一步导入的 StaticRouter 组件包裹一下以前生成的服务端渲染组件
    2019-07-27-09-24-17

代码diff

最后的最后, 咱们执行一下 node index.js, 浏览器打开 localhost:9999

react-router-ssr

经过 gif 咱们能发现, 咱们的服务端渲染是货真价实的服务端渲染了. 查看源代码的 html 字符串没有任何的问题了.(若是有样式该咋办呢 🤔)

细心的同窗可能发现了, 咱们每次点击连接的时候页面都会总体刷新. 这里就又到了那个经典的面试题前端:你要懂的单页面应用和多页面应用, 咱们的目的很简单, 只是须要 ssr 实现首屏的渲染, 以后就由客户端接管, 这样就结合了二者的优势. 需求是有了, 怎么实现咧~

====================

2019-07-27-09-38-00

====================

聪明的同窗已经猜到, 只要咱们咱们在服务端渲染的页面中也引入客户端渲染生成的 bundle.js 文件是否是就 OK 了呢.那咱们就试试咯

2019-07-27-09-41-08

修改 server.js 引入 koa-static 用于托管静态文件, 文件总体 diff 以下:

2019-07-27-09-43-36

废话少扯, 继续 node index.js, 浏览器打开 localhost:9999 搞起~

react-router-dont-reload

服务端渲染的路由配置, 这就完成了~

9150e4e5gy1g53l5pua7og208c08c0tr

配置 redux, 带上身份畅玩澳门皇冠

客户端渲染引入 redux

因为配置 redux 不是咱们的重点, 因此这里就很少说了, 简单配置一个 redux 开发环境. 代码 diff

有疑问的问题, 评论区见~

2019-07-27-12-26-06

ssr 引入 redux

修改 server.js 文件以下:

import path from 'path';
import Koa from 'koa';
import Router from 'koa-router';
import React from 'react';
import { renderToString } from 'react-dom/server';
import { StaticRouter } from 'react-router-dom';
import serve from 'koa-static';

// 像客户端渲染同样导入 Provider 组件
import { Provider } from 'react-redux';
import App from './components/App.jsx';
import createStore, { init } from './store';

const app = new Koa();
const router = new Router();

const conf = {
  PORT: 9999,
};

const generateHtmlStr = reactDom => `
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>

    <div id="app">${reactDom}</div>
    <script src="/dist/bundle.js"></script>
</body>
</html>
`;

router.get('*', (ctx) => {
  const context = {};
  const { url } = ctx.req;

  // 初始化一个 store
  const store = createStore();

  // 手动触发一下 init
  store.dispatch(init());
  // 首先把 React 组件变成一个字符串
  // eslint-disable-next-line
  const rNode = renderToString(
    // 把刚刚建立的 store 做为属性传给 Provider 组件
    <Provider store={store}>
      <StaticRouter location={url} context={context}>
        <App />
      </StaticRouter>
    </Provider>,
  );
  // 而后替换 template 里边的内容
  const domString = generateHtmlStr(rNode);

  // 最后返回 html 字符串
  ctx.body = domString;
});

app.use(serve(path.resolve(__dirname, '../')));
app.use(router.routes(), router.allowedMethods());

app.listen(conf.PORT, () => {
  console.log(`The Server is listening on ${conf.PORT} now, enjoy`);
});
复制代码

代码 diff 以下:

2019-07-27-17-32-51

仍是那一套, 先 node index.js 再浏览器打开 localhost:9999~

2019-07-27-17-37-54

浏览器执行结果以下图:

redux-ssr

细心的同窗不难发现, 这个图片中抓牌的入口老是会闪动一下, 理论上讲咱们执行了 store.dispatch(init()); 证实了用户是已经登陆的用户, 因此应该是能够抓牌的才对. 这是问啥呢???

2019-07-27-17-46-45

其实缘由很简单, 咱们的项目在首屏渲染完成之后就有客户端渲染接管了, 因此咱们应该在客户端接管的时候把以前服务端渲染的数据保留下来. 怎么搞呢?

  • 首先, 获取首屏状况下的状态
  • 其次, 升级 server.js 文件, generateHtmlStr 中添加一个参数, 表示当前的状态
  • 再次, 更新 html 模板, 在 window 下建立一个 REDUX_DATA 属性, 用于放置服务端渲染时首屏的全局状态
  • 最后, 升级客户端相关的代码, 在 createStore 的时候把 REDUX_DATA 做为参数传入. 也正所以, 定义 REDUX_DATA 要放在引入 bundle.js 的上方.

这就完了, 经过下边的 gif 能够看出, 状态很好的保存下来了~

redux-ssr-goog

到了这里, 可能有同窗会问, 咱们来到皇冠赌场, 全局状态确定会灰常的多, 不该该只有一个登录状态. 鉴于此, 咱们扩充一下全局状态. 添加一个音乐列表. 一遍欢歌一遍看牌~

下来咱们在看牌页面添加一个音乐列表, 咱们听着音乐看着牌, 要是再吃着火锅那简直就是人生巅峰了.

2019-08-16-10-16-02

在 store 中获取异步数据

  • 首先, 咱们建立一个 mock.js, 主要就是访问异步接口获取歌曲列表
import axios from 'axios';

export default () => axios('https://music.niubishanshan.top/api/v2/music/toplist')
  .then(({ data }) => data);

// 在 mock.js 中咱们引用了高端的 ajax 请求库 axios. 那么就不得不 npm i axios -S 啦
复制代码
  • 其次, 升级 store.js 添加歌曲相关的 actions 和 reducer.
    2019-08-16-11-31-25
  • 因为咱们有以前的单 reducer 升级成了两个 reducer, 此时要同步升级以前链接过 redux 的组件 Header Home Zhuapai
  • 最后, 在看牌页面, 咱们引入音乐. party Time
    2019-08-16-11-40-48

到目前为止, 代码是 这样 的.

废话少说...

error-kanpai

1565938746

卧槽, 竟然很差使...

仔细看一下, 原来是 action 里边不能包含异步. 这个简单. 咱们升级一下.

而后...

ok-kanpai

服务端渲染支持首屏展现初始异步数据

有的时候, 咱们服务端渲染的首屏网页也须要从其余异步接口来获取初始化数据. 此时就须要吧 html 返回给前端前先去访问异步接口. 那么怎么办咧...

最后...

11a88f499af3f3b5d80b756fd

polyfill-error

这里建议你们复习一下 polyfill 和 preset 的区别

反正我就这么干了一把

而后就...

polyfill-ok

是否是能够痛快的玩耍啦 😺~

42cdf9611d1efb032b2b5b396
相关文章
相关标签/搜索