Skip to content

Commit afd76ef

Browse files
fix(addons-react): prevent fluxibleRef to leak in connected components (#752)
1 parent 2ba3719 commit afd76ef

File tree

3 files changed

+46
-16
lines changed

3 files changed

+46
-16
lines changed

packages/fluxible-addons-react/src/connectToStores.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,12 @@ function connectToStores(Component, stores, getStateFromStores, options) {
6262
}
6363

6464
render() {
65-
const storeState = getStateFromStores(this.context, this.props);
65+
const { fluxibleRef, ...props } = this.props;
66+
const storeState = getStateFromStores(this.context, props);
6667

6768
return createElement(Component, {
68-
ref: this.props.fluxibleRef,
69-
...this.props,
69+
ref: fluxibleRef,
70+
...props,
7071
...storeState,
7172
});
7273
}
@@ -75,10 +76,12 @@ function connectToStores(Component, stores, getStateFromStores, options) {
7576
StoreConnector.contextType = FluxibleComponentContext;
7677

7778
const forwarded = forwardRef((props, ref) =>
78-
createElement(StoreConnector, {
79-
...props,
80-
fluxibleRef: options?.forwardRef ? ref : null,
81-
})
79+
createElement(
80+
StoreConnector,
81+
options?.forwardRef
82+
? Object.assign({ fluxibleRef: ref }, props)
83+
: props
84+
)
8285
);
8386
forwarded.displayName = `storeConnector(${
8487
Component.displayName || Component.name || 'Component'

packages/fluxible-addons-react/tests/unit/lib/FluxibleComponentContext.test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const React = require('react');
22
const { useContext } = require('react');
33
const { renderToString } = require('react-dom/server');
4-
const { FluxibleComponent, FluxibleComponentContext } = require('../../../');
4+
const { FluxibleProvider, FluxibleComponentContext } = require('../../../');
55

66
describe('FluxibleComponentContext', () => {
77
it('provides access to getStore and executeAction', () => {
@@ -20,9 +20,9 @@ describe('FluxibleComponentContext', () => {
2020
};
2121

2222
renderToString(
23-
<FluxibleComponent context={context}>
23+
<FluxibleProvider context={context}>
2424
<Component />
25-
</FluxibleComponent>
25+
</FluxibleProvider>
2626
);
2727

2828
expect(context.getStore).toHaveBeenCalledTimes(1);

packages/fluxible-addons-react/tests/unit/lib/connectToStores.test.js

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const {
88
} = require('react');
99
const TestRenderer = require('react-test-renderer');
1010
const createMockComponentContext = require('fluxible/utils/createMockComponentContext');
11-
const { connectToStores, FluxibleComponent } = require('../../../');
11+
const { connectToStores, FluxibleProvider } = require('../../../');
1212
const FooStore = require('../../fixtures/stores/FooStore');
1313
const BarStore = require('../../fixtures/stores/BarStore');
1414

@@ -40,15 +40,18 @@ const renderComponent = (Component, ref) => {
4040
const context = createMockComponentContext({ stores });
4141

4242
const app = TestRenderer.create(
43-
<FluxibleComponent context={context}>
43+
<FluxibleProvider context={context}>
4444
<Component ref={ref} />
45-
</FluxibleComponent>
45+
</FluxibleProvider>
4646
);
4747

4848
return { app, context };
4949
};
5050

51-
const getComponent = (app) => app.root.findByType(DumbComponent);
51+
const getComponent = (app, component) => app.root.findByType(component);
52+
53+
const getStoreConnector = (app) =>
54+
app.root.find((node) => node.type.name === 'StoreConnector');
5255

5356
describe('fluxible-addons-react', () => {
5457
describe('connectToStores', () => {
@@ -80,7 +83,7 @@ describe('fluxible-addons-react', () => {
8083

8184
it('should forward props from getStateFromStores to component', () => {
8285
const { app } = renderComponent(ConnectedComponent);
83-
const component = getComponent(app);
86+
const component = getComponent(app, DumbComponent);
8487

8588
expect(component.props.foo).toBe('bar');
8689
expect(component.props.bar).toBe('baz');
@@ -89,7 +92,7 @@ describe('fluxible-addons-react', () => {
8992

9093
it('should listen to store changes', () => {
9194
const { app } = renderComponent(ConnectedComponent);
92-
const component = getComponent(app);
95+
const component = getComponent(app, DumbComponent);
9396

9497
component.props.onClick();
9598

@@ -156,6 +159,30 @@ describe('fluxible-addons-react', () => {
156159
renderComponent(ConnectedForwardComponent, ref2);
157160
expect(ref2.current.number).toBe(24);
158161
});
162+
163+
it('does not pass fluxibleRef to StoreConnector if ref is disabled', () => {
164+
const ref = createRef(null);
165+
const { app } = renderComponent(ConnectedComponent, ref);
166+
167+
const connector = app.root.find(
168+
(node) => node.type.name === 'StoreConnector'
169+
);
170+
expect(connector.props.fluxibleRef).toBe(undefined);
171+
172+
const component = getComponent(app, ConnectedComponent);
173+
expect(component.props.fluxibleRef).toBe(undefined);
174+
});
175+
176+
it('does not leak fluxibleRef to inner component', () => {
177+
const ref = createRef(null);
178+
const { app } = renderComponent(ConnectedClassComponent, ref);
179+
180+
const connector = getStoreConnector(app);
181+
expect(connector.props.fluxibleRef).not.toBe(undefined);
182+
183+
const component = getComponent(app, ConnectedClassComponent);
184+
expect(component.props.fluxibleRef).toBe(undefined);
185+
});
159186
});
160187
});
161188
});

0 commit comments

Comments
 (0)