Skip to content

Commit 34f2368

Browse files
committed
Don't create a new object as Context value, as this would trigger unnecessary rerenders of Consumers, just use state for everything.
1 parent 139c0a2 commit 34f2368

File tree

2 files changed

+57
-39
lines changed

2 files changed

+57
-39
lines changed

src/index.js

Lines changed: 33 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
11
import React from "react"
22

3-
const getInitialState = () => ({
4-
messages: [],
5-
errors: [],
6-
data: undefined,
7-
error: undefined,
8-
updatedAt: undefined,
9-
lastPostAt: undefined
10-
})
11-
12-
const uninitialized = () => {
13-
throw new Error("Not initialized")
14-
}
15-
16-
const { Consumer, Provider } = React.createContext(getInitialState())
3+
const { Consumer, Provider } = React.createContext()
174

185
class WebWorker extends React.Component {
19-
state = getInitialState()
6+
constructor(props) {
7+
super(props)
8+
this.state = {
9+
messages: [],
10+
errors: [],
11+
data: undefined,
12+
error: undefined,
13+
updatedAt: undefined,
14+
lastPostAt: undefined,
15+
postMessage: this.postMessage
16+
}
17+
}
18+
19+
uninitialized = () => {
20+
throw new Error("Worker not initialized")
21+
}
2022

2123
onMessage = message => {
2224
if (!this.mounted) return
@@ -39,7 +41,7 @@ class WebWorker extends React.Component {
3941

4042
postMessage = data => {
4143
const { serializer = x => x } = this.props
42-
const { postMessage = uninitialized } = this.worker || {}
44+
const { postMessage = this.uninitialized } = this.worker || {}
4345
this.setState({ lastPostAt: new Date() }, () => postMessage.call(this.worker, serializer(data)))
4446
}
4547

@@ -49,7 +51,6 @@ class WebWorker extends React.Component {
4951
this.worker.onmessage = this.onMessage
5052
this.worker.onerror = this.onError
5153
this.mounted = true
52-
this.setState(getInitialState())
5354
}
5455

5556
componentWillUnmount() {
@@ -59,19 +60,12 @@ class WebWorker extends React.Component {
5960

6061
render() {
6162
const { children } = this.props
62-
const renderProps = {
63-
...this.state,
64-
postMessage: this.postMessage
65-
}
66-
6763
if (typeof children === "function") {
68-
return <Provider value={renderProps}>{children(renderProps)}</Provider>
64+
return <Provider value={this.state}>{children(this.state)}</Provider>
6965
}
70-
7166
if (children !== undefined && children !== null) {
72-
return <Provider value={renderProps}>{children}</Provider>
67+
return <Provider value={this.state}>{children}</Provider>
7368
}
74-
7569
return null
7670
}
7771
}
@@ -80,42 +74,42 @@ class WebWorker extends React.Component {
8074
* Renders only when no message or error has been received yet
8175
*
8276
* @prop {boolean} persist Show until we have data, even when an error occurred
83-
* @prop {Function|Node} children Function (passing props) or React node
77+
* @prop {Function|Node} children Function (passing state) or React node
8478
*/
8579
WebWorker.Pending = ({ children, persist }) => (
8680
<Consumer>
87-
{props => {
88-
if (props.data !== undefined) return null
89-
if (!persist && props.error !== undefined) return null
90-
return typeof children === "function" ? children(props) : children || null
81+
{state => {
82+
if (state.data !== undefined) return null
83+
if (!persist && state.error !== undefined) return null
84+
return typeof children === "function" ? children(state) : children || null
9185
}}
9286
</Consumer>
9387
)
9488

9589
/**
9690
* Renders only when worker has sent a message with data
9791
*
98-
* @prop {Function|Node} children Function (passing data and props) or React node
92+
* @prop {Function|Node} children Function (passing data and state) or React node
9993
*/
10094
WebWorker.Data = ({ children }) => (
10195
<Consumer>
102-
{props => {
103-
if (props.data === undefined) return null
104-
return typeof children === "function" ? children(props.data, props) : children || null
96+
{state => {
97+
if (state.data === undefined) return null
98+
return typeof children === "function" ? children(state.data, state) : children || null
10599
}}
106100
</Consumer>
107101
)
108102

109103
/**
110104
* Renders only when worker has sent an error
111105
*
112-
* @prop {Function|Node} children Function (passing error and props) or React node
106+
* @prop {Function|Node} children Function (passing error and state) or React node
113107
*/
114108
WebWorker.Error = ({ children }) => (
115109
<Consumer>
116-
{props => {
117-
if (props.error === undefined) return null
118-
return typeof children === "function" ? children(props.error, props) : children || null
110+
{state => {
111+
if (state.error === undefined) return null
112+
return typeof children === "function" ? children(state.error, state) : children || null
119113
}}
120114
</Consumer>
121115
)

src/spec.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,3 +194,27 @@ test("WebWorker.Pending renders only when no error has been received yet", async
194194
worker.onerror({ error: "foo" })
195195
expect(queryByText("pending")).toBeNull()
196196
})
197+
198+
test("An unrelated change in props does not update the Context", async () => {
199+
let one
200+
let two
201+
const { rerender } = render(
202+
<WebWorker>
203+
<WebWorker.Pending>
204+
{value => {
205+
one = value
206+
}}
207+
</WebWorker.Pending>
208+
</WebWorker>
209+
)
210+
rerender(
211+
<WebWorker someProp>
212+
<WebWorker.Pending>
213+
{value => {
214+
two = value
215+
}}
216+
</WebWorker.Pending>
217+
</WebWorker>
218+
)
219+
expect(one).toBe(two)
220+
})

0 commit comments

Comments
 (0)