Skip to content

Commit cd25b62

Browse files
tills13Andarist
andauthored
Use theme context when rendering components at all times (#2424)
* unconditionally use useContext * add changeset * Update .changeset/light-swans-guess.md: major -> patch Co-authored-by: Mateusz Burzyński <[email protected]> * 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 <[email protected]>
1 parent a69929d commit cd25b62

File tree

5 files changed

+92
-7
lines changed

5 files changed

+92
-7
lines changed

.changeset/light-swans-guess.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@emotion/react': patch
3+
---
4+
5+
6+
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.

packages/react/__tests__/element.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// @flow
2+
/** @jsx jsx */
3+
import 'test-utils/dev-mode'
4+
import { render } from 'react-dom'
5+
import { jsx, css, CacheProvider, ThemeProvider } from '@emotion/react'
6+
import createCache from '@emotion/cache'
7+
8+
// $FlowFixMe
9+
console.error = jest.fn()
10+
11+
beforeEach(() => {
12+
// $FlowFixMe
13+
document.head.innerHTML = ''
14+
// $FlowFixMe
15+
document.body.innerHTML = `<div id="root"></div>`
16+
17+
jest.clearAllMocks()
18+
})
19+
20+
describe('EmotionElement', () => {
21+
test('no React hook order violations', () => {
22+
const theme = { color: 'blue' }
23+
const cache = createCache({ key: 'context' })
24+
25+
// $FlowFixMe
26+
const Comp = ({ flag }) => (
27+
<ThemeProvider theme={theme}>
28+
<CacheProvider value={cache}>
29+
<div
30+
css={
31+
flag &&
32+
(t => css`
33+
color: ${t.color};
34+
`)
35+
}
36+
/>
37+
</CacheProvider>
38+
</ThemeProvider>
39+
)
40+
41+
render(<Comp />, document.getElementById('root'))
42+
expect(console.error).not.toHaveBeenCalled()
43+
render(<Comp flag />, document.getElementById('root'))
44+
expect(console.error).not.toHaveBeenCalled()
45+
})
46+
})

packages/react/__tests__/global.js

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,25 @@
22
import 'test-utils/dev-mode'
33
import * as React from 'react'
44
import { render, unmountComponentAtNode } from 'react-dom'
5-
import { Global, keyframes, css, CacheProvider } from '@emotion/react'
5+
import {
6+
Global,
7+
keyframes,
8+
css,
9+
CacheProvider,
10+
ThemeProvider
11+
} from '@emotion/react'
612
import createCache from '@emotion/cache'
713

14+
// $FlowFixMe
15+
console.error = jest.fn()
16+
817
beforeEach(() => {
918
// $FlowFixMe
1019
document.head.innerHTML = ''
1120
// $FlowFixMe
1221
document.body.innerHTML = `<div id="root"></div>`
22+
23+
jest.resetAllMocks()
1324
})
1425

1526
test('basic', () => {
@@ -67,3 +78,29 @@ test('updating more than 1 global rule', () => {
6778
renderComponent({ background: 'gray', color: 'white' })
6879
expect(document.head).toMatchSnapshot()
6980
})
81+
82+
test('no React hook order violations', () => {
83+
const theme = { color: 'blue' }
84+
const cache = createCache({ key: 'context' })
85+
86+
// $FlowFixMe
87+
const Comp = ({ flag }) => (
88+
<ThemeProvider theme={theme}>
89+
<CacheProvider value={cache}>
90+
<Global
91+
styles={
92+
flag &&
93+
(t => css`
94+
color: ${t.color};
95+
`)
96+
}
97+
/>
98+
</CacheProvider>
99+
</ThemeProvider>
100+
)
101+
102+
render(<Comp />, document.getElementById('root'))
103+
expect(console.error).not.toHaveBeenCalled()
104+
render(<Comp flag />, document.getElementById('root'))
105+
expect(console.error).not.toHaveBeenCalled()
106+
})

packages/react/src/emotion-element.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,7 @@ let Emotion = /* #__PURE__ */ withEmotionCache<any, any>(
8888
let serialized = serializeStyles(
8989
registeredStyles,
9090
undefined,
91-
typeof cssProp === 'function' || Array.isArray(cssProp)
92-
? React.useContext(ThemeContext)
93-
: undefined
91+
React.useContext(ThemeContext)
9492
)
9593

9694
if (

packages/react/src/global.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,7 @@ export let Global: React.AbstractComponent<GlobalProps> =
4040
let serialized = serializeStyles(
4141
[styles],
4242
undefined,
43-
typeof styles === 'function' || Array.isArray(styles)
44-
? React.useContext(ThemeContext)
45-
: undefined
43+
React.useContext(ThemeContext)
4644
)
4745

4846
if (!isBrowser) {

0 commit comments

Comments
 (0)