Skip to content

Commit fec9a03

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 b658bfc commit fec9a03

File tree

2 files changed

+67
-47
lines changed

2 files changed

+67
-47
lines changed

src/index.js

Lines changed: 43 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,26 @@ export const createInstance = (defaultProps = {}) => {
88
const { Consumer, Provider } = React.createContext()
99

1010
class Async extends React.Component {
11-
mounted = false
12-
counter = 0
13-
args = []
14-
state = {
15-
data: undefined,
16-
error: undefined,
17-
isLoading: false,
18-
startedAt: undefined,
19-
finishedAt: undefined
11+
constructor(props) {
12+
super(props)
13+
this.mounted = false
14+
this.counter = 0
15+
this.args = []
16+
this.state = {
17+
data: undefined,
18+
error: undefined,
19+
isLoading: false,
20+
startedAt: undefined,
21+
finishedAt: undefined,
22+
cancel: this.cancel,
23+
run: this.run,
24+
reload: () => {
25+
this.load()
26+
this.run(...this.args)
27+
},
28+
setData: this.setData,
29+
setError: this.setError
30+
}
2031
}
2132

2233
componentDidMount() {
@@ -83,27 +94,12 @@ export const createInstance = (defaultProps = {}) => {
8394

8495
render() {
8596
const { children } = this.props
86-
87-
const renderProps = {
88-
...this.state,
89-
cancel: this.cancel,
90-
run: this.run,
91-
reload: () => {
92-
this.load()
93-
this.run(...this.args)
94-
},
95-
setData: this.setData,
96-
setError: this.setError
97-
}
98-
9997
if (typeof children === "function") {
100-
return <Provider value={renderProps}>{children(renderProps)}</Provider>
98+
return <Provider value={this.state}>{children(this.state)}</Provider>
10199
}
102-
103100
if (children !== undefined && children !== null) {
104-
return <Provider value={renderProps}>{children}</Provider>
101+
return <Provider value={this.state}>{children}</Provider>
105102
}
106-
107103
return null
108104
}
109105
}
@@ -112,15 +108,15 @@ export const createInstance = (defaultProps = {}) => {
112108
* Renders only when deferred promise is pending (not yet run).
113109
*
114110
* @prop {boolean} persist Show until we have data, even while loading or when an error occurred
115-
* @prop {Function|Node} children Function (passing props) or React node
111+
* @prop {Function|Node} children Function (passing state) or React node
116112
*/
117113
Async.Pending = ({ children, persist }) => (
118114
<Consumer>
119-
{props => {
120-
if (props.data !== undefined) return null
121-
if (!persist && props.isLoading) return null
122-
if (!persist && props.error !== undefined) return null
123-
return typeof children === "function" ? children(props) : children || null
115+
{state => {
116+
if (state.data !== undefined) return null
117+
if (!persist && state.isLoading) return null
118+
if (!persist && state.error !== undefined) return null
119+
return typeof children === "function" ? children(state) : children || null
124120
}}
125121
</Consumer>
126122
)
@@ -129,14 +125,14 @@ export const createInstance = (defaultProps = {}) => {
129125
* Renders only while loading.
130126
*
131127
* @prop {boolean} initial Show only on initial load (data is undefined)
132-
* @prop {Function|Node} children Function (passing props) or React node
128+
* @prop {Function|Node} children Function (passing state) or React node
133129
*/
134130
Async.Loading = ({ children, initial }) => (
135131
<Consumer>
136-
{props => {
137-
if (!props.isLoading) return null
138-
if (initial && props.data !== undefined) return null
139-
return typeof children === "function" ? children(props) : children || null
132+
{state => {
133+
if (!state.isLoading) return null
134+
if (initial && state.data !== undefined) return null
135+
return typeof children === "function" ? children(state) : children || null
140136
}}
141137
</Consumer>
142138
)
@@ -145,14 +141,14 @@ export const createInstance = (defaultProps = {}) => {
145141
* Renders only when promise is resolved.
146142
*
147143
* @prop {boolean} persist Show old data while loading
148-
* @prop {Function|Node} children Function (passing data and props) or React node
144+
* @prop {Function|Node} children Function (passing data and state) or React node
149145
*/
150146
Async.Resolved = ({ children, persist }) => (
151147
<Consumer>
152-
{props => {
153-
if (props.data === undefined) return null
154-
if (props.isLoading && !persist) return null
155-
return typeof children === "function" ? children(props.data, props) : children || null
148+
{state => {
149+
if (state.data === undefined) return null
150+
if (state.isLoading && !persist) return null
151+
return typeof children === "function" ? children(state.data, state) : children || null
156152
}}
157153
</Consumer>
158154
)
@@ -161,14 +157,14 @@ export const createInstance = (defaultProps = {}) => {
161157
* Renders only when promise is rejected.
162158
*
163159
* @prop {boolean} persist Show old error while loading
164-
* @prop {Function|Node} children Function (passing error and props) or React node
160+
* @prop {Function|Node} children Function (passing error and state) or React node
165161
*/
166162
Async.Rejected = ({ children, persist }) => (
167163
<Consumer>
168-
{props => {
169-
if (props.error === undefined) return null
170-
if (props.isLoading && !persist) return null
171-
return typeof children === "function" ? children(props.error, props) : children || null
164+
{state => {
165+
if (state.error === undefined) return null
166+
if (state.isLoading && !persist) return null
167+
return typeof children === "function" ? children(state.error, state) : children || null
172168
}}
173169
</Consumer>
174170
)

src/spec.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,3 +307,27 @@ test("createInstance allows setting default props", async () => {
307307
await waitForElement(() => getByText("done"))
308308
expect(onResolve).toHaveBeenCalledWith("done")
309309
})
310+
311+
test("An unrelated change in props does not update the Context", async () => {
312+
let one
313+
let two
314+
const { rerender } = render(
315+
<Async>
316+
<Async.Pending>
317+
{value => {
318+
one = value
319+
}}
320+
</Async.Pending>
321+
</Async>
322+
)
323+
rerender(
324+
<Async someProp>
325+
<Async.Pending>
326+
{value => {
327+
two = value
328+
}}
329+
</Async.Pending>
330+
</Async>
331+
)
332+
expect(one).toBe(two)
333+
})

0 commit comments

Comments
 (0)