Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d8d2b6e

Browse files
authored
Disable module components dynamically for WWW (facebook#18446)
* Make disableModulePatternComponents dynamic for WWW * Run both flags and tests and respect the flag in SSR
1 parent e2c6702 commit d8d2b6e

18 files changed

+505
-402
lines changed

packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js

Lines changed: 57 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -983,64 +983,66 @@ describe('ReactComponentLifeCycle', () => {
983983
});
984984
});
985985

986-
it('calls effects on module-pattern component', function() {
987-
const log = [];
986+
if (!require('shared/ReactFeatureFlags').disableModulePatternComponents) {
987+
it('calls effects on module-pattern component', function() {
988+
const log = [];
988989

989-
function Parent() {
990-
return {
991-
render() {
992-
expect(typeof this.props).toBe('object');
993-
log.push('render');
994-
return <Child />;
995-
},
996-
UNSAFE_componentWillMount() {
997-
log.push('will mount');
998-
},
999-
componentDidMount() {
1000-
log.push('did mount');
1001-
},
1002-
componentDidUpdate() {
1003-
log.push('did update');
1004-
},
1005-
getChildContext() {
1006-
return {x: 2};
1007-
},
990+
function Parent() {
991+
return {
992+
render() {
993+
expect(typeof this.props).toBe('object');
994+
log.push('render');
995+
return <Child />;
996+
},
997+
UNSAFE_componentWillMount() {
998+
log.push('will mount');
999+
},
1000+
componentDidMount() {
1001+
log.push('did mount');
1002+
},
1003+
componentDidUpdate() {
1004+
log.push('did update');
1005+
},
1006+
getChildContext() {
1007+
return {x: 2};
1008+
},
1009+
};
1010+
}
1011+
Parent.childContextTypes = {
1012+
x: PropTypes.number,
1013+
};
1014+
function Child(props, context) {
1015+
expect(context.x).toBe(2);
1016+
return <div />;
1017+
}
1018+
Child.contextTypes = {
1019+
x: PropTypes.number,
10081020
};
1009-
}
1010-
Parent.childContextTypes = {
1011-
x: PropTypes.number,
1012-
};
1013-
function Child(props, context) {
1014-
expect(context.x).toBe(2);
1015-
return <div />;
1016-
}
1017-
Child.contextTypes = {
1018-
x: PropTypes.number,
1019-
};
1020-
1021-
const div = document.createElement('div');
1022-
expect(() =>
1023-
ReactDOM.render(<Parent ref={c => c && log.push('ref')} />, div),
1024-
).toErrorDev(
1025-
'Warning: The <Parent /> component appears to be a function component that returns a class instance. ' +
1026-
'Change Parent to a class that extends React.Component instead. ' +
1027-
"If you can't use a class try assigning the prototype on the function as a workaround. " +
1028-
'`Parent.prototype = React.Component.prototype`. ' +
1029-
"Don't use an arrow function since it cannot be called with `new` by React.",
1030-
);
1031-
ReactDOM.render(<Parent ref={c => c && log.push('ref')} />, div);
1032-
1033-
expect(log).toEqual([
1034-
'will mount',
1035-
'render',
1036-
'did mount',
1037-
'ref',
10381021

1039-
'render',
1040-
'did update',
1041-
'ref',
1042-
]);
1043-
});
1022+
const div = document.createElement('div');
1023+
expect(() =>
1024+
ReactDOM.render(<Parent ref={c => c && log.push('ref')} />, div),
1025+
).toErrorDev(
1026+
'Warning: The <Parent /> component appears to be a function component that returns a class instance. ' +
1027+
'Change Parent to a class that extends React.Component instead. ' +
1028+
"If you can't use a class try assigning the prototype on the function as a workaround. " +
1029+
'`Parent.prototype = React.Component.prototype`. ' +
1030+
"Don't use an arrow function since it cannot be called with `new` by React.",
1031+
);
1032+
ReactDOM.render(<Parent ref={c => c && log.push('ref')} />, div);
1033+
1034+
expect(log).toEqual([
1035+
'will mount',
1036+
'render',
1037+
'did mount',
1038+
'ref',
1039+
1040+
'render',
1041+
'did update',
1042+
'ref',
1043+
]);
1044+
});
1045+
}
10441046

10451047
it('should warn if getDerivedStateFromProps returns undefined', () => {
10461048
class MyComponent extends React.Component {

packages/react-dom/src/__tests__/ReactCompositeComponent-test.js

Lines changed: 45 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -108,26 +108,53 @@ describe('ReactCompositeComponent', () => {
108108
};
109109
});
110110

111-
it('should support module pattern components', () => {
112-
function Child({test}) {
113-
return {
114-
render() {
115-
return <div>{test}</div>;
116-
},
117-
};
118-
}
111+
if (require('shared/ReactFeatureFlags').disableModulePatternComponents) {
112+
it('should not support module pattern components', () => {
113+
function Child({test}) {
114+
return {
115+
render() {
116+
return <div>{test}</div>;
117+
},
118+
};
119+
}
119120

120-
const el = document.createElement('div');
121-
expect(() => ReactDOM.render(<Child test="test" />, el)).toErrorDev(
122-
'Warning: The <Child /> component appears to be a function component that returns a class instance. ' +
123-
'Change Child to a class that extends React.Component instead. ' +
124-
"If you can't use a class try assigning the prototype on the function as a workaround. " +
125-
'`Child.prototype = React.Component.prototype`. ' +
126-
"Don't use an arrow function since it cannot be called with `new` by React.",
127-
);
121+
const el = document.createElement('div');
122+
expect(() => {
123+
expect(() => ReactDOM.render(<Child test="test" />, el)).toThrow(
124+
'Objects are not valid as a React child (found: object with keys {render}).',
125+
);
126+
}).toErrorDev(
127+
'Warning: The <Child /> component appears to be a function component that returns a class instance. ' +
128+
'Change Child to a class that extends React.Component instead. ' +
129+
"If you can't use a class try assigning the prototype on the function as a workaround. " +
130+
'`Child.prototype = React.Component.prototype`. ' +
131+
"Don't use an arrow function since it cannot be called with `new` by React.",
132+
);
128133

129-
expect(el.textContent).toBe('test');
130-
});
134+
expect(el.textContent).toBe('');
135+
});
136+
} else {
137+
it('should support module pattern components', () => {
138+
function Child({test}) {
139+
return {
140+
render() {
141+
return <div>{test}</div>;
142+
},
143+
};
144+
}
145+
146+
const el = document.createElement('div');
147+
expect(() => ReactDOM.render(<Child test="test" />, el)).toErrorDev(
148+
'Warning: The <Child /> component appears to be a function component that returns a class instance. ' +
149+
'Change Child to a class that extends React.Component instead. ' +
150+
"If you can't use a class try assigning the prototype on the function as a workaround. " +
151+
'`Child.prototype = React.Component.prototype`. ' +
152+
"Don't use an arrow function since it cannot be called with `new` by React.",
153+
);
154+
155+
expect(el.textContent).toBe('test');
156+
});
157+
}
131158

132159
it('should support rendering to different child types over time', () => {
133160
const instance = ReactTestUtils.renderIntoDocument(<MorphingComponent />);

packages/react-dom/src/__tests__/ReactCompositeComponentState-test.js

Lines changed: 46 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -459,55 +459,57 @@ describe('ReactCompositeComponent-state', () => {
459459
]);
460460
});
461461

462-
it('should support stateful module pattern components', () => {
463-
function Child() {
464-
return {
465-
state: {
466-
count: 123,
467-
},
468-
render() {
469-
return <div>{`count:${this.state.count}`}</div>;
470-
},
471-
};
472-
}
462+
if (!require('shared/ReactFeatureFlags').disableModulePatternComponents) {
463+
it('should support stateful module pattern components', () => {
464+
function Child() {
465+
return {
466+
state: {
467+
count: 123,
468+
},
469+
render() {
470+
return <div>{`count:${this.state.count}`}</div>;
471+
},
472+
};
473+
}
473474

474-
const el = document.createElement('div');
475-
expect(() => ReactDOM.render(<Child />, el)).toErrorDev(
476-
'Warning: The <Child /> component appears to be a function component that returns a class instance. ' +
477-
'Change Child to a class that extends React.Component instead. ' +
478-
"If you can't use a class try assigning the prototype on the function as a workaround. " +
479-
'`Child.prototype = React.Component.prototype`. ' +
480-
"Don't use an arrow function since it cannot be called with `new` by React.",
481-
);
475+
const el = document.createElement('div');
476+
expect(() => ReactDOM.render(<Child />, el)).toErrorDev(
477+
'Warning: The <Child /> component appears to be a function component that returns a class instance. ' +
478+
'Change Child to a class that extends React.Component instead. ' +
479+
"If you can't use a class try assigning the prototype on the function as a workaround. " +
480+
'`Child.prototype = React.Component.prototype`. ' +
481+
"Don't use an arrow function since it cannot be called with `new` by React.",
482+
);
482483

483-
expect(el.textContent).toBe('count:123');
484-
});
484+
expect(el.textContent).toBe('count:123');
485+
});
485486

486-
it('should support getDerivedStateFromProps for module pattern components', () => {
487-
function Child() {
488-
return {
489-
state: {
490-
count: 1,
491-
},
492-
render() {
493-
return <div>{`count:${this.state.count}`}</div>;
494-
},
495-
};
496-
}
497-
Child.getDerivedStateFromProps = (props, prevState) => {
498-
return {
499-
count: prevState.count + props.incrementBy,
487+
it('should support getDerivedStateFromProps for module pattern components', () => {
488+
function Child() {
489+
return {
490+
state: {
491+
count: 1,
492+
},
493+
render() {
494+
return <div>{`count:${this.state.count}`}</div>;
495+
},
496+
};
497+
}
498+
Child.getDerivedStateFromProps = (props, prevState) => {
499+
return {
500+
count: prevState.count + props.incrementBy,
501+
};
500502
};
501-
};
502503

503-
const el = document.createElement('div');
504-
ReactDOM.render(<Child incrementBy={0} />, el);
505-
expect(el.textContent).toBe('count:1');
504+
const el = document.createElement('div');
505+
ReactDOM.render(<Child incrementBy={0} />, el);
506+
expect(el.textContent).toBe('count:1');
506507

507-
ReactDOM.render(<Child incrementBy={2} />, el);
508-
expect(el.textContent).toBe('count:3');
508+
ReactDOM.render(<Child incrementBy={2} />, el);
509+
expect(el.textContent).toBe('count:3');
509510

510-
ReactDOM.render(<Child incrementBy={1} />, el);
511-
expect(el.textContent).toBe('count:4');
512-
});
511+
ReactDOM.render(<Child incrementBy={1} />, el);
512+
expect(el.textContent).toBe('count:4');
513+
});
514+
}
513515
});

packages/react-dom/src/__tests__/ReactDOMServerIntegrationElements-test.js

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -644,16 +644,33 @@ describe('ReactDOMServerIntegration', () => {
644644
checkFooDiv(await render(<ClassComponent />));
645645
});
646646

647-
itRenders('factory components', async render => {
648-
const FactoryComponent = () => {
649-
return {
650-
render: function() {
651-
return <div>foo</div>;
652-
},
647+
if (require('shared/ReactFeatureFlags').disableModulePatternComponents) {
648+
itThrowsWhenRendering(
649+
'factory components',
650+
async render => {
651+
const FactoryComponent = () => {
652+
return {
653+
render: function() {
654+
return <div>foo</div>;
655+
},
656+
};
657+
};
658+
await render(<FactoryComponent />, 1);
659+
},
660+
'Objects are not valid as a React child (found: object with keys {render})',
661+
);
662+
} else {
663+
itRenders('factory components', async render => {
664+
const FactoryComponent = () => {
665+
return {
666+
render: function() {
667+
return <div>foo</div>;
668+
},
669+
};
653670
};
654-
};
655-
checkFooDiv(await render(<FactoryComponent />, 1));
656-
});
671+
checkFooDiv(await render(<FactoryComponent />, 1));
672+
});
673+
}
657674
});
658675

659676
describe('component hierarchies', function() {

0 commit comments

Comments
 (0)