Skip to content

Commit

Permalink
Use theme context when rendering components at all times (#2424)
Browse files Browse the repository at this point in the history
* unconditionally use useContext

* add changeset

* Update .changeset/light-swans-guess.md: major -> patch

Co-authored-by: Mateusz Burzyński <mateuszburzynski@gmail.com>

* update global.js with fix

* tests to ensure serializeStyles is always invoked with theme

* adjust tests

* Update .changeset/light-swans-guess.md

Co-authored-by: Mateusz Burzyński <mateuszburzynski@gmail.com>
  • Loading branch information
tills13 and Andarist authored Aug 8, 2021
1 parent a69929d commit cd25b62
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 7 deletions.
6 changes: 6 additions & 0 deletions .changeset/light-swans-guess.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@emotion/react': patch
---


Use theme context when rendering components at all times. This removes a conditional usage of a React hook that could break [Rules of Hooks](https://reactjs.org/docs/hooks-rules.html) in some scenarios.
46 changes: 46 additions & 0 deletions packages/react/__tests__/element.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// @flow
/** @jsx jsx */
import 'test-utils/dev-mode'
import { render } from 'react-dom'
import { jsx, css, CacheProvider, ThemeProvider } from '@emotion/react'
import createCache from '@emotion/cache'

// $FlowFixMe
console.error = jest.fn()

beforeEach(() => {
// $FlowFixMe
document.head.innerHTML = ''
// $FlowFixMe
document.body.innerHTML = `<div id="root"></div>`

jest.clearAllMocks()
})

describe('EmotionElement', () => {
test('no React hook order violations', () => {
const theme = { color: 'blue' }
const cache = createCache({ key: 'context' })

// $FlowFixMe
const Comp = ({ flag }) => (
<ThemeProvider theme={theme}>
<CacheProvider value={cache}>
<div
css={
flag &&
(t => css`
color: ${t.color};
`)
}
/>
</CacheProvider>
</ThemeProvider>
)

render(<Comp />, document.getElementById('root'))
expect(console.error).not.toHaveBeenCalled()
render(<Comp flag />, document.getElementById('root'))
expect(console.error).not.toHaveBeenCalled()
})
})
39 changes: 38 additions & 1 deletion packages/react/__tests__/global.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,25 @@
import 'test-utils/dev-mode'
import * as React from 'react'
import { render, unmountComponentAtNode } from 'react-dom'
import { Global, keyframes, css, CacheProvider } from '@emotion/react'
import {
Global,
keyframes,
css,
CacheProvider,
ThemeProvider
} from '@emotion/react'
import createCache from '@emotion/cache'

// $FlowFixMe
console.error = jest.fn()

beforeEach(() => {
// $FlowFixMe
document.head.innerHTML = ''
// $FlowFixMe
document.body.innerHTML = `<div id="root"></div>`

jest.resetAllMocks()
})

test('basic', () => {
Expand Down Expand Up @@ -67,3 +78,29 @@ test('updating more than 1 global rule', () => {
renderComponent({ background: 'gray', color: 'white' })
expect(document.head).toMatchSnapshot()
})

test('no React hook order violations', () => {
const theme = { color: 'blue' }
const cache = createCache({ key: 'context' })

// $FlowFixMe
const Comp = ({ flag }) => (
<ThemeProvider theme={theme}>
<CacheProvider value={cache}>
<Global
styles={
flag &&
(t => css`
color: ${t.color};
`)
}
/>
</CacheProvider>
</ThemeProvider>
)

render(<Comp />, document.getElementById('root'))
expect(console.error).not.toHaveBeenCalled()
render(<Comp flag />, document.getElementById('root'))
expect(console.error).not.toHaveBeenCalled()
})
4 changes: 1 addition & 3 deletions packages/react/src/emotion-element.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,7 @@ let Emotion = /* #__PURE__ */ withEmotionCache<any, any>(
let serialized = serializeStyles(
registeredStyles,
undefined,
typeof cssProp === 'function' || Array.isArray(cssProp)
? React.useContext(ThemeContext)
: undefined
React.useContext(ThemeContext)
)

if (
Expand Down
4 changes: 1 addition & 3 deletions packages/react/src/global.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@ export let Global: React.AbstractComponent<GlobalProps> =
let serialized = serializeStyles(
[styles],
undefined,
typeof styles === 'function' || Array.isArray(styles)
? React.useContext(ThemeContext)
: undefined
React.useContext(ThemeContext)
)

if (!isBrowser) {
Expand Down

0 comments on commit cd25b62

Please sign in to comment.