美文网首页
JSS与React的集成

JSS与React的集成

作者: vincent_z | 来源:发表于2019-10-05 21:00 被阅读0次

    介绍

    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

    相关文章

      网友评论

          本文标题:JSS与React的集成

          本文链接:https://www.haomeiwen.com/subject/mskypctx.html