0x0 React16新特性
官网:https://reactjs.org/
新特性官方说明
- react+react-dom包大小:40k → 30k
- 整个代码都用Fiber重新了
- error boundary
- 捕获react渲染过程中的错误
- 可以在正式环境中,弹个提醒告诉用户
- 错误日志,辅助排错
- 开发中排错
- new render return types
- render function中支持直接返回数组、字符串
- Protals:可以在组件中,把一个标签强制插入到页面任意其他标签下
- 服务端渲染的升级 - 可以使用「流」的方式做渲染了
- 在有服务端渲染的情况下,使用hydrate方法渲染客户端内容
0x1 Material-UI的安装和使用
官网:https://www.material-ui.com/
说明:React components that implement Google's Material Design
注意:需要考虑到服务端渲染相关配置
特点:直接在js里面写css文件,可以有非常好的动态性
目标:展示出来Material-UI的一个Button
基础使用 & 配置服务端渲染
安装
https://material-ui.com/getting-started/installation/
pm i @material-ui/core @material-ui/icons -S 知识兔td> |
基本使用
app.js
..
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core'
import { lightBlue, pink } from '@material-ui/core/colors'
...
const theme = createMuiTheme({ # 1
palette: {
primary: lightBlue,
accent: pink,
type: 'light',
},
})
...
const render = (Component) => {
ReactDOM.hydrate(
...
<MuiThemeProvider theme={theme}> # 2
<Component />
</MuiThemeProvider>
...
)
}; 知识兔td> |
说明:
- 创建调色盘
- 定义主色
- 定义辅助色
- 定义通过「亮度」区分差异色
- 传入theme & 包裹Component
topic-list/index.jsx
业务组件
..
import Button from '@material-ui/core/Button'
...
render() {
return (
...
<Button variant="contained" color="primary">
不...不要点我...
</Button>
...
)
}
} 知识兔td> |
说明:
- Button组件相关API:https://material-ui.com/api/button/
效果
说明:
- 由于未做服务端渲染,故访问2333端口无法看到此按钮效果
- 检查元素可以看到,相关css的style已经插入到该页面中
服务端渲染
https://material-ui.com/guides/server-rendering/#server-rendering
安装插件:`npm i react-jss jss jss-preset-default -S`
server-entry.js
..
import { JssProvider } from 'react-jss'
import { MuiThemeProvider } from '@material-ui/core/styles'
...
export default (store, routerContext, sheetsRegistry, jss, theme, url) => (
...
<JssProvider registry={sheetsRegistry} jss={jss}>
<MuiThemeProvider theme={theme}>
<App />
</MuiThemeProvider>
</JssProvider>
...
) 知识兔td> |
说明:
- 入口需要添加JssProvider和MuiThemeProvider的包裹
server-render.js
..
const SheetsRegistry = require('react-jss').SheetsRegistry
const create = require('jss').create
const preset = require('jss-preset-default').default
const createMuiTheme = require('@material-ui/core/styles').createMuiTheme
const createGenerateClassName = require('@material-ui/core/styles/createGenerateClassName').default
const colors = require('@material-ui/core/colors')
...
module.exports = (bundle, template, req, res) => {
return new Promise((resolve, reject) => {
...
const sheetRegistry = new SheetsRegistry()
const jss = create(preset())
jss.options.createGenerateClassName = createGenerateClassName
const theme = createMuiTheme({
palette: {
primary: colors.lightBlue,
accent: colors.pink,
type: 'light',
},
})
const app = createApp(stores, routerContext, sheetRegistry, jss, theme, req.url)
asyncBootstrapper(app).then(() => {
...
const html = ejs.render(template, {
...
materialCss: sheetRegistry.toString(), // #1
})
...
}).catch(reject)
})
} 知识兔td> |
说明:
- 把jss样式渲染成css样式,传入到html模板中
server.template.ejs
..
<head>
...
<style>
<%%- materialCss %>
</style>
</head>
... 知识兔td> |
说明:
- 把渲染好的css样式插入到模板文件中
- 效果
- 可以看到,生成的css 已经被插入进来了
删除重复的CSS定义
需要在客户端侧,渲染完成之后,把这些css删掉,防止冲突
思路:给服务端渲染生成的style添加id,之后通过id拿到标签做删除
server.template.ejs
..
<head>
...
<style id="jss-server-side">
<%%- materialCss %>
</style>
</head>
... 知识兔td> |
app.js
..
const createApp = (TheApp) => {
class Main extends React.Component {
componentDidMount() {
const jssStyles = document.getElementById('jss-server-side')
if (jssStyles && jssStyles.parentNode) {
jssStyles.parentNode.removeChild(jssStyles)
}
}
render() {
return <TheApp />
}
}
return Main
}
const render = (Component) => {
const ComponentR = createApp(Component)
ReactDOM.hydrate(
...
<ComponentR />
...
)
}
... 知识兔td> |
说明: