JSS与React的集成

本文详细介绍了React-JSS如何利用新的Hooks API与React集成,包括动态主题、关键CSS提取、惰性评估等功能。文章展示了从基于HOC的API转换到使用`createUseStyles`的示例,解释了如何创建和应用样式,以及如何实现动态值、主题化和类名生成器的选项。此外,还涵盖了服务端渲染的处理方法。
摘要由CSDN通过智能技术生成

介绍

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>
    )
  )
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值