Skip to content

Commit f879801

Browse files
committed
fix(overmind-react): forward ref to connected component
1 parent c9bad57 commit f879801

File tree

3 files changed

+64
-16
lines changed

3 files changed

+64
-16
lines changed

packages/node_modules/overmind-react/src/__snapshots__/index.test.tsx.snap

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,9 @@ exports[`React should connect state and actions to stateless components 1`] = `
4141
bar
4242
</h1>
4343
`;
44+
45+
exports[`React should forward ref 1`] = `
46+
<h1>
47+
bar
48+
</h1>
49+
`;

packages/node_modules/overmind-react/src/index.test.tsx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,4 +398,33 @@ describe('React', () => {
398398
.toJSON()
399399
}).toThrow(Error)
400400
})
401+
test('should forward ref', () => {
402+
const app = new Overmind({})
403+
404+
const connect = createConnect<{}>()
405+
406+
const expected = "bar"
407+
408+
class ForwardComponent extends React.Component<IConnect<{}>> {
409+
foo = expected
410+
render() {
411+
return <h1>{this.foo}</h1>
412+
}
413+
}
414+
415+
const ConnectedFoo = connect(ForwardComponent)
416+
417+
const ref = React.createRef<ForwardComponent>();
418+
419+
const tree = renderer
420+
.create(
421+
<Provider value={app}>
422+
<ConnectedFoo ref={ref} />
423+
</Provider>
424+
)
425+
.toJSON()
426+
427+
expect(ref.current?.foo).toBe(expected)
428+
expect(tree).toMatchSnapshot()
429+
})
401430
})

packages/node_modules/overmind-react/src/index.ts

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ function useForceRerender() {
8484
}, [])
8585

8686
return {
87-
flushId,
87+
flushId,
8888
forceRerender
8989
}
9090
}
@@ -211,7 +211,6 @@ const useState = <Config extends IConfiguration>(): Overmind<Config>['state'] =
211211
}
212212
})
213213
}
214-
215214

216215
return trackingRef.current.tree.state
217216
}
@@ -222,7 +221,7 @@ const useActions = <Config extends IConfiguration>(): Overmind<Config>['actions
222221
if (!(overmind as any).mode) {
223222
throwMissingContextError()
224223
}
225-
224+
226225
return overmind.actions
227226
}
228227

@@ -232,7 +231,7 @@ const useEffects = <Config extends IConfiguration>(): Overmind<Config>['effects
232231
if (!(overmind as any).mode) {
233232
throwMissingContextError()
234233
}
235-
234+
236235
return overmind.effects
237236
}
238237

@@ -242,7 +241,7 @@ const useReaction = <Config extends IConfiguration>(): Overmind<Config>['reacti
242241
if (!(overmind as any).mode) {
243242
throwMissingContextError()
244243
}
245-
244+
246245
return overmind.reaction
247246
}
248247

@@ -285,23 +284,23 @@ export const createHook: <Config extends IConfiguration>() => () => {
285284
}
286285
}
287286

288-
export const createConnect: <ThisConfig extends IConfiguration>() => <Props>(component: IReactComponent<
289-
Props & {
287+
export const createConnect: <ThisConfig extends IConfiguration>() =>
288+
<Props, TComponent extends IReactComponent<Props & {
290289
overmind: {
291290
state: Overmind<ThisConfig>['state']
292291
actions: Overmind<ThisConfig>['actions']
293292
reaction: Overmind<ThisConfig>['reaction']
294293
}
295294
}
296-
>) => IReactComponent<
295+
>>(component: TComponent) => IReactComponent<
297296
Omit<
298-
Props & IConnect<Overmind<ThisConfig>>,
297+
react.ComponentPropsWithRef<TComponent> & IConnect<Overmind<ThisConfig>>,
299298
keyof IConnect<Overmind<ThisConfig>>
300299
>
301-
> = () => {
300+
> = <Props, TComponent extends IReactComponent>() => {
302301
return (
303302
component
304-
)=> {
303+
) => {
305304
let componentInstanceId = 0
306305
const name = component.displayName || component.name || 'Anonymous';
307306
const populatedComponent = component as any
@@ -327,7 +326,7 @@ export const createConnect: <ThisConfig extends IConfiguration>() => <Props>(com
327326
}
328327

329328
if (IS_PRODUCTION) {
330-
class HOC extends react.Component {
329+
class HOC extends react.Component<{innerRef: react.Ref<TComponent>}> {
331330
tree: any
332331
overmind: any
333332
state: {
@@ -380,20 +379,27 @@ export const createConnect: <ThisConfig extends IConfiguration>() => <Props>(com
380379
if (isClassComponent) {
381380
return react.createElement(component, {
382381
...this.props,
382+
ref: this.props.innerRef,
383383
overmind: this.state.overmind,
384384
} as any)
385385
}
386386

387387
return react.createElement(this.wrappedComponent, {
388388
...this.props,
389+
ref: this.props.innerRef,
389390
overmind: this.state.overmind,
390391
} as any)
391392
}
392393
}
393394

394-
return HOC as any
395+
const refForwarder = react.forwardRef<TComponent, Props>((props, ref) => react.createElement(HOC, {
396+
...props,
397+
innerRef: ref
398+
}))
399+
400+
return refForwarder
395401
} else {
396-
class HOC extends react.Component {
402+
class HOC extends react.Component<{innerRef: react.Ref<TComponent>}> {
397403
tree: any
398404
overmind: any
399405
componentInstanceId = componentInstanceId++
@@ -477,23 +483,30 @@ export const createConnect: <ThisConfig extends IConfiguration>() => <Props>(com
477483
if (isClassComponent) {
478484
return react.createElement(component, {
479485
...this.props,
486+
ref: this.props.innerRef,
480487
overmind: this.state.overmind,
481488
} as any)
482489
}
483490
return react.createElement(this.wrappedComponent, {
484491
...this.props,
492+
ref: this.props.innerRef,
485493
overmind: this.state.overmind,
486494
} as any)
487495
}
488496
}
489497

490-
Object.defineProperties(HOC, {
498+
const refForwarder = react.forwardRef<TComponent, Props>((props, ref) => react.createElement(HOC, {
499+
...props,
500+
innerRef: ref
501+
}))
502+
503+
Object.defineProperties(refForwarder, {
491504
name: {
492505
value: 'Connect' + name,
493506
},
494507
})
495508

496-
return HOC as any
509+
return refForwarder
497510
}
498511
}
499512
}

0 commit comments

Comments
 (0)