浅谈react 同构之样式直出(5)

疑问三:@withStyles是什么语法?

答:这个是装饰器,属于es7。使用该语法,需要配置tsconfig:

// ./tsconfig.json
// ./src/webpack/tsconfig.client(server).json

{
 ...
 "compilerOptions": {
  ...
  "experimentalDecorators": true,
  ...
 },
 ...
}

改写服务端bundle文件

由于App组件的改写,服务端不能再复用该组件,但是AppProvider和AppContent目前还是可以复用的。

// ./src/server/bundle.tsx

import * as React from 'react';

/* tslint:disable-next-line no-submodule-imports */
import { renderToString } from 'react-dom/server';

import AppProvider from '../client/component/app/provider';

import AppContent from '../client/component/app/content';

export default {
 render() {
  const css = [];
  const context = { insertCss: (...styles) => styles.forEach((s) => css.push(s._getCss())) };
  const html = renderToString(
   <AppProvider context={context}>
    <AppContent />
   </AppProvider>,
  );
  const style = css.join('');
  return {
   html,
   style,
  };
 },
};

这里我们传入了自定义的context对象,通过css这个变量来存储style信息。我们原先render函数直接返回renderToString的html字符串,而现在多了一个style,所以我们返回拥有html和style属性的对象。

疑问四:官方示例css是一个Set类型实例,这里怎么是一个数组类型实例?

答:Set是es6中新的数据结构,类似数组,但可以保证无重复值,只有tsconfig的编译选项中的target为es6时,且加入es2017的lib时才不会报错,由于我们的target是es5,所以是数组,且使用数组并没有太大问题。

处理服务端入口文件

由于bundle的render值变更,所以我们也要处理一下。

// ./src/server/index.tsx

...
router.get('/*', (ctx: Koa.Context, next) => { // 配置一个简单的get通配路由
 const renderResult = bundle ? bundle.render() : {}; // 获得渲染出的结果对象
 const { html = '', style = '' } = renderResult;
 ...
 ctx.body = `
  ...
  <head>
   ...
   ${style ? `<style>${style}</style>` : ''}
   ...
  </head>
  ...
 `;
 ...
});
...

直出结果

样式直出后的page source:

找回丢失的公共样式文件

从上面的直出结果来看,缺少./src/style/index.pcss这个样式代码,原因显而易见,它不属于任何一个组件,它是公共的,我们在客户端入口文件里引入了它。对于公共样式文件,服务端要直出这部分内容,可以这么做:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/1079.html