JSS与React的集成
2019-10-05 本文已影响0人
vincent_z
介绍
React-JSS使用新的Hooks API将JSS与React集成在一起。 JSS和默认预设已经内置。
从v10开始,不支持基于HOC的API,并将在所有即将发布的主要版本中将其删除。如下的使用方式将不支持。
import React from 'react'
import {render} from 'react-dom'
import withStyles from 'react-jss'
// 1、创建styles
const styles = {
...
}
// 2、使用这些样式定义组件,并将其传递给classes属性,使用它来分配作用域类名
const Button = ({classes, children}) => (
<button className={classes.myButton}>
<span className={classes.myLabel}>{children}</span>
</button>
)
// 3、最后,将样式表注入组件
const StyledButton = withStyles(styles)(Button)
// 或 4、导出组件
export default withStyles(styles)(Button)
// 5、使用
const App = () => <StyledButton>Submit</StyledButton>
render(<App />, document.getElementById('root'))
与直接使用核心JSS软件包相比,其好处是:
- 动态主题-允许基于上下文的主题传播和运行时更新。
- 关键CSS提取-仅从呈现的组件中提取CSS。
- 惰性评估-样式表是在安装组件时创建的,而在卸载组件时被删除的。
- 样式表的静态部分将在所有元素之间共享。
- 函数值和规则会随你传递给useStyles(data)的任何数据自动更新。例如,你可以传递道具,状态或上下文中的任何内容。
基本使用
import React from 'react'
import {render} from 'react-dom'
import {createUseStyles} from 'react-jss'
// 1、创建样式
const useStyles = createUseStyles({
myButton: {
color: 'green',
margin: {
// jss-plugin-expand插件让语法可读性更高
top: 5, // jss-plugin-default-unit插件补全单位
right: 0,
bottom: 0,
left: '1rem'
},
'& span': {
// jss-plugin-nested 插件将样式应用到子节点
fontWeight: 'bold' // jss-plugin-camel-case插件将fontWegith转化为font-weight
}
},
myLabel: {
fontStyle: 'italic'
},
})
// 2、使用这些样式定义组件,并将其传递给classes属性,使用它来分配作用域类名
const Button = ({children}) => {
const classes = useStyles() // 使用样式
return (
<button className={classes.myButton}>
<span className={classes.myLabel}>{children}</span>
</button>
)
}
// 3、使用组件
const App = () => <Button>Submit</Button>
render(<App />, document.getElementById('root'))
上面的代码编译为
<div id="root">
<button class="Button-myButton-0-1-24">
<span class="myLabel-0-1-87">
Submit
</span>
</button>
</div>
.myButton-0-1-24 {
color: green;
margin: 5px 0 0 1rem;
}
.myButton-0-1-24 span {
font-weight: bold;
}
.myLabel-0-1-87 {
font-style: italic;
}
动态值
你可以直接使用函数值,函数规则和可观察对象。一旦组件第一次接收到新的props或mount,函数值和函数规则将接收props对象。
注意事项:
首先呈现静态属性,以便函数值具有更高的源顺序特异性:
import React from 'react'
import {createUseStyles} from 'react-jss'
const useStyles = createUseStyles({
myButton: {
padding: props => props.spacing
},
myLabel: props => ({
display: 'block',
color: props.labelColor,
fontWeight: props.fontWeight,
fontStyle: props.fontStyle
})
})
const Button = ({children, ...props}) => {
const classes = useStyles(props)
return (
<button className={classes.myButton}>
<span className={classes.myLabel}>{children}</span>
</button>
)
}
Button.defaultProps = {
spacing: 10,
fontWeight: 'bold',
labelColor: 'red'
}
const App = () => <Button fontStyle="italic">Submit</Button>
上面的代码编译为
<div id="root">
<button class="Button-myButton-1-25">
<span class="Button-myLabel-1-26">
Submit
</span>
</button>
</div>
.Button-myButton-1-25 {
padding: 10px;
}
.Button-myLabel-1-26 {
display: block;
color: red;
font-weight: bold;
font-style: italic;
}
主题化
主题化指定义一个主题,用ThemeProvider
包装应用程序,然后将主题对象传递给ThemeProvider
。稍后,你可以在样式创建器函数(createUseStyles ((theme) => { ... })
)中使用useTheme()
挂钩来访问主题。之后,你可以更改主题,所有组件都将自动获得新主题。
在幕后,react-jss为React使用了独立的主题解决方案。你可以在其回购中找到完整的文档。
ThemeProvider
的用法:
- 它有一个
theme
prop,使用一个object
或function
表示:
- 如果它是一个
Object
并在根ThemeProvider
中使用,则它是完整的并向下传递到React Tree
。- 如果它是Object并在嵌套的
ThemeProvider中
使用,则它将与父ThemeProvider
的主题合并,并向下传递到React Tree
。- 如果它是
Function
并在嵌套的ThemeProvide
r中使用,则它将从父``ThemeProvider应用于主题。如果结果是一个
Object,它将沿着
React Tree```向下传递,否则抛出。
-
ThemeProvider
和其他所有组件一样,只能渲染一个child
,因为它在渲染中使用React.Children.only
,否则抛出。
import React from 'react'
import {createUseStyles, useTheme, ThemeProvider} from 'react-jss'
// 1、当有很多主题依赖关系时,最好使用theme函数
let useStyles = createUseStyles(theme => ({
button: {
background: theme.colorPrimary
},
label: {
fontWeight: 'bold'
}
}))
// 或者如果只有很少的主题相关样式,则使用函数值可能会更好,并且props或state也用于其他值
useStyles = createUseStyles({
button: {
background: ({theme}) => theme.colorPrimary
},
label: {
fontWeight: 'bold'
}
})
// 2、定义组件,传入theme、props等
const Button = ({children, ...props}) => {
const theme = useTheme()
const classes = useStyles({...props, theme})
return (
<button className={classes.button}>
<span className={classes.label}>{children}</span>
</button>
)
}
const theme = {
colorPrimary: 'green'
}
// 定义主题及使用组件
const App = () => (
<ThemeProvider theme={theme}>
<Button>I am a button with green background</Button>
</ThemeProvider>
)
使用自定义主题上下文
使用命名空间主题,这样一组UI组件就不会与其他库中的另一组UI组件发生冲突(也可以使用react-jss
),或者如果你想从应用程序中已使用的另一个上下文中使用同一主题,则不会发生冲突。
import React from 'react'
import {createUseStyles, createTheming} from 'react-jss'
const ThemeContext = React.createContext({})
// 创建一个具有命名空间的主题对象
const theming = createTheming(ThemeContext)
// 注意这里的useTheme来自theming对象,而不是来自react-jss导入。
const {ThemeProvider, useTheme} = theming
const useStyles = createUseStyles(
{
button: {
background: ({theme}) => theme.colorPrimary
}
// 将theming对象传递给createUseStyles()
},
{theming}
)
const myTheme = {
colorPrimary: 'green'
}
const Button = ({children, ...props}) => {
const theme = useTheme()
const classes = useStyles({...props, theme})
return <button className={classes.button}>{children}</button>
}
const OtherLibraryThemeProvider = () => null
const OtherLibraryComponent = () => null
const otherLibraryTheme = {}
// 使用具有命名空间的主题ThemeProviders-它们可以以任何顺序嵌套
const App = () => (
<OtherLibraryThemeProvider theme={otherLibraryTheme}>
<OtherLibraryComponent />
<ThemeProvider theme={myTheme}>
<Button>Green Button</Button>
</ThemeProvider>
</OtherLibraryThemeProvider>
)
类名生成器选项
确保在服务器和客户端上使用相同的设置。ID生成器用于类名和关键帧。
1、你可以通过传递自定义生成器函数来更改类名称生成算法。
import React from 'react'
import ReactDOM from 'react-dom'
import {JssProvider} from 'react-jss'
import MyApp from './MyApp'
const generateId = (rule, sheet) => 'some-id'
ReactDOM.render(
<JssProvider generateId={generateId}>
<MyApp />
</JssProvider>,
document.getElementById('root')
)
2、你可以为每个类添加其他前缀,详见。
3、你可以通过传递id
属性来最小化类名,详见。
import React from 'react'
import ReactDOM from 'react-dom'
import {JssProvider} from 'react-jss'
import MyApp from './MyApp'
ReactDOM.render(
<JssProvider id={{minify: true}}>
<MyApp />
</JssProvider>,
document.getElementById('root')
)
服务端渲染
挂载应用程序后,应删除关键CSS呈现的服务器端使用的样式标签。
import React from 'react'
import {renderToString} from 'react-dom/server'
import {JssProvider, SheetsRegistry, createGenerateId} from 'react-jss'
import MyApp from './MyApp'
export default function render(req, res) {
const sheets = new SheetsRegistry()
const generateId = createGenerateId()
const body = renderToString(
<JssProvider registry={sheets} generateId={generateId}>
<MyApp />
</JssProvider>
)
//任何在<MyApp />中使用useStyles的实例都将获得样式表
return res.send(
renderToString(
<html lang="en">
<head>
<style type="text/css">{sheets.toString()}</style>
</head>
<body>{body}</body>
</html>
)
)
}
参考
JSS