JSS与React的集成

介绍

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的用法:

  • 它有一个themeprop,使用一个objectfunction表示:
  • 如果它是一个Object并在根ThemeProvider中使用,则它是完整的并向下传递到React Tree
  • 如果它是Object并在嵌套的ThemeProvider中使用,则它将与父ThemeProvider的主题合并,并向下传递到React Tree
  • 如果它是Function并在嵌套的ThemeProvider中使用,则它将从父``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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260