直出样式
我们利用isomorphic-style-loader来实现服务端直出样式,原理的话根据官方介绍就是利用了react的context api来实现,在服务端渲染的过程中,利用注入的insertCss方法和高阶组件(hoc high-order component)来获取样式代码。
安装依赖
npm install prop-types --save-dev
改写App组件
根据其官方介绍,我们在不使用其整合完毕的isomorphic router的情况下,需要写一个Provider给App组件:
// ./src/client/component/app/provider.tsx
import * as React from 'react';
import * as PropTypes from 'prop-types';
class AppProvider extends React.PureComponent<any, any> {
public static propTypes = {
context: PropTypes.object,
};
public static defaultProps = {
context: {
insertCss: () => '',
},
};
public static childContextTypes = {
insertCss: PropTypes.func.isRequired,
};
public getChildContext() {
return this.props.context;
}
public render() {
return this.props.children || null;
}
}
export default AppProvider;
将原App组件里的具体内容迁移到AppContent组件里去:
// ./src/client/component/app/content.tsx
import * as React from 'react';
import * as styles from './style.pcss';
/* tslint:disable-next-line no-submodule-imports */
import withStyles from 'isomorphic-style-loader/lib/withStyles';
@withStyles(styles)
class AppContent extends React.PureComponent {
public render() {
return (
<div className={styles.root}>hello world</div>
);
}
}
export default AppContent;
新的App组件:
// ./src/client/component/app/index.tsx
import * as React from 'react';
import AppProvider from './provider';
import AppContent from './content';
class App extends React.PureComponent {
public render() {
return (
<AppProvider>
<AppContent />
</AppProvider>
);
}
}
export default App;
疑问一:AppProvider组件是做什么的?
答:Provider的意思是 供应者,提供者 。顾名思义,AppProvider为其后代组件提供了一些东西,这个东西就是context,它有一个insertCss方法。根据其定义,该方法拥有默认值,返回空字符串的函数,即默认没什么作用,但是可以通过props传入context来达到自定义的目的。通过设定childContextTypes和getChildContext,该组件后代凡是设定了contextTypes的组件都会拥有this.context对象,而这个对象正是getChildContext的返回值。
疑问二:AppContent为何要独立出去?
答:接上一疑问,AppProvider组件render其子组件,而要使得context这个api生效,其子组件必须是定义了contextTypes的,但是我们并没有看见AppContent有这个定义,这个是因为这个定义在高阶组件withStyles里面(参见其 源码 )。
