Skip to content

Commit

Permalink
Add useStyles(style) hook for React.js (#159)
Browse files Browse the repository at this point in the history
* feat: useStyles to support Hooks

* Add note of `useStyles` to docs
  • Loading branch information
piglovesyou authored and frenzzy committed May 27, 2019
1 parent bd5af84 commit c647f58
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 0 deletions.
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,28 @@ ReactDOM.hydrate(
)
```

**React Hooks Support:**

You can also use `useStyles` inside your React Functional Components, instead of using `withStyles`.
Please note that you still need to pass `insertCss` function to `StyleContext.Provider` from top of the tree.

```js
import React from 'react'
import useStyles from 'isomorphic-style-loader/useStyles'
import s from './App.scss'

const App = (props) => {
useStyles(s);
return (
<div className={s.root}>
<h1 className={s.title}>Hello, world!</h1>
</div>
)
};

export default App;
```

## Related Projects

* [React Starter Kit](https://github.com/kriasoft/react-starter-kit)
Expand Down
36 changes: 36 additions & 0 deletions src/useStyles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* Isomorphic CSS style loader for Webpack
*
* Copyright © 2015-present Kriasoft, LLC. All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE.txt file in the root directory of this source tree.
*/

import { useContext, useEffect } from 'react'
import StyleContext from './StyleContext'

// To detect if it's in SSR process or in browser. Wrapping with
// the function makes rollup's replacement of "this" avoidable
// eslint-disable-next-line func-names
const isBrowser = (function() {
return this && typeof this.window === 'object'
})()

function useStyles(...styles) {
const { insertCss } = useContext(StyleContext)
if (!insertCss) throw new Error('Please provide "insertCss" function by StyleContext.Provider')
const runEffect = () => {
const removeCss = insertCss(...styles)
return () => {
setTimeout(removeCss, 0)
}
}
if (isBrowser) {
useEffect(runEffect, [])
} else {
runEffect()
}
}

export default useStyles
51 changes: 51 additions & 0 deletions test/useStyles.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* Isomorphic CSS style loader for Webpack
*
* Copyright © 2015-present Kriasoft, LLC. All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE.txt file in the root directory of this source tree.
*/

import React, { Component, Children } from 'react'
import PropTypes from 'prop-types'
import ReactDOM from 'react-dom'
import useStyles from '../src/useStyles'
import StyleContext from '../src/StyleContext'

describe('useStyles(...styles)', () => {
it('Should call insertCss and removeCss functions provided by context', () => {
class Provider extends Component {
render() {
const { insertCss, children } = this.props
return (
<StyleContext.Provider value={{ insertCss }}>
{Children.only(children)}
</StyleContext.Provider>
)
}
}

Provider.propTypes = {
insertCss: PropTypes.func.isRequired,
children: PropTypes.node.isRequired,
}

const FooWithStyles = () => {
useStyles('')
return <div />
}

const insertCss = jest.fn(() => {})
const container = global.document.createElement('div')

ReactDOM.render(
<Provider insertCss={insertCss}>
<FooWithStyles />
</Provider>,
container,
)
ReactDOM.unmountComponentAtNode(container)
expect(insertCss).toBeCalledTimes(1)
})
})
7 changes: 7 additions & 0 deletions tools/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ const files = [
external: ['react', 'hoist-non-react-statics', path.resolve('dist/src/StyleContext.js')],
paths: { [path.resolve('dist/src/StyleContext.js')]: './StyleContext.js' },
},
{
input: 'dist/src/useStyles.js',
output: 'dist/useStyles.js',
format: 'cjs',
external: ['react', path.resolve('dist/src/StyleContext.js')],
paths: { [path.resolve('dist/src/StyleContext.js')]: './StyleContext.js' },
},
{
input: 'dist/src/StyleContext.js',
output: 'dist/StyleContext.js',
Expand Down

0 comments on commit c647f58

Please sign in to comment.