直出样式
我们利用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里面(参见其 源码 )。