isomorphic-style-loader在前后端渲染样式同构中的应用与源码分析

前言

在笔者的上一篇文章(基于react的前后端渲染实例讲解)中,对react下前后端渲染的流程进行了一个介绍。对前后端渲染的相关概念和原理不太了解的可以移步那篇文章。同时留下了一个引子:如何优雅地实现前后端渲染的样式同构。由此我们引出了公共库isomorphic-style-loader,在这篇文章中,笔者将结合实例介绍该库在项目中的应用以及对其原理进行分析。

项目实战

这里我们以上一篇文章中的测试项目为基础,借助isomorphic-style-loader来实现前后端渲染的样式同构。仓库地址附在文末。项目的主干部分不变,具体的区别在于前端和后端渲染的入口文件以及业务组件。

业务组件

业务组件代码(entry/component/index.js)如下:

import React from 'react';
import s from './color.css';
import withStyles from 'isomorphic-style-loader/withStyles';
import useStyles from 'isomorphic-style-loader/useStyles';
//  传统写法 class式组件亦可
function ShowComponent(props, context) {
   
    return <div className={
   s.color}>英雄的中国人民万岁!</div>
}
export default withStyles(s)(ShowComponent);

这里主要是借助库内提供的withStyles对我们的原始组件进行处理,后续样式标签的自动添加和删除都会通过库来实现。isomorphic-style-loader对react的hooks特性也进行了兼容,使用hooks组件的写法如下:

//  省略部分依赖引用
//  react hooks 写法 
const ShowComponent = () => {
   
    useStyles(s);
    return <div className={
   s.color}>英雄的中国人民万岁万岁!</div>
}
export default ShowComponent;

前端渲染入口

在前端渲染的入口文件(entry/index.js)也要进行对应的处理:

import React from 'react';
import ReactDom from 'react-dom';
import Com from './component';
import StyleContext from 'isomorphic-style-loader/StyleContext';

const insertCss = (...styles) => {
   
    const removeCss = styles.map(style => style._insertCss())
    return () => removeCss.forEach(dispose => dispose())
}
//  挂载组件
const mountNode = document.getElementById('main');

//  原始前端渲染 在html的节点上挂载组件
// ReactDom.render((
//     <Com />
// ),mountNode);

ReactDom.hydrate(
    <StyleContext.Provider value={
   {
    insertCss }}>
      <Com />
    </StyleContext.Provider>,
    mountNode
);

这里通过react的context语法,给我们的入口组件包裹一个StyleContext,便于后续子组件调用insertCss方法。insertCss遍历所有的css文件,并执行内置的_insertCss(源码分析中会做分析)方法,该方法负责实时在html文件中插入style标签以便跟新样式,该方法同时返回一个函数,用于在组件移除时同步删除样式标签。

后端渲染入口

后端渲染的入口文件也要做类似处理:

import React from 'react';
import ServerEntry from './component/index';
import ReactSSR from 'react-dom/server';
import StyleContext from 'isomorphic-style-loader/StyleContext';

function serverRender(res, template) {
   
  const css = new Set();
  const insertCss = (...styles) => styles.forEach(style => css.add(style._getCss()))
  const appString = ReactSSR.renderToString(
      <StyleContext.Provider value={
   {
    insertCss }}>
        <ServerEntry />
      </StyleContext.Provider>
    );
  //    返回模板被替换后的内容,这里将app标签替换成组件,style标签替换成所需的样式
  res
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值