Skip to content

Commit e42a988

Browse files
Merge pull request #1394 from creative-commoners/pulls/6/refactor-more-comp
ENH Refactor more react components from class to functional
2 parents a290149 + 8a966fd commit e42a988

12 files changed

Lines changed: 1452 additions & 367 deletions

File tree

client/dist/js/bundle.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 68 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,73 @@
1-
import React, { PureComponent } from 'react';
1+
import React, { memo } from 'react';
22
import PropTypes from 'prop-types';
33
import { inject } from 'lib/Injector';
44
import { compose } from 'redux';
55

6-
class Content extends PureComponent {
7-
render() {
8-
const {
9-
id,
10-
fileUrl,
11-
fileTitle,
12-
content,
13-
previewExpanded,
14-
InlineEditFormComponent,
15-
SummaryComponent,
16-
activeTab,
17-
onFormInit,
18-
handleLoadingError,
19-
formDirty,
20-
broken,
21-
onFormSchemaSubmitResponse,
22-
ensureFormRendered,
23-
formHasRendered,
24-
} = this.props;
6+
const Content = ({
7+
id,
8+
fileUrl,
9+
fileTitle,
10+
content,
11+
previewExpanded,
12+
InlineEditFormComponent,
13+
SummaryComponent,
14+
activeTab,
15+
onFormInit,
16+
handleLoadingError,
17+
formDirty,
18+
broken,
19+
onFormSchemaSubmitResponse,
20+
ensureFormRendered,
21+
formHasRendered,
22+
}) => {
23+
// The '*-rendered-not-visible` class is used to hide the form when it's not visible
24+
// It will be rendered off screen via css rather than using display: none because
25+
// the form needs to be rendered in order to be submitted
26+
const notVisible = !previewExpanded && (ensureFormRendered || formHasRendered);
27+
const extraClass = {
28+
'element-editor-editform--collapsed': !previewExpanded,
29+
'element-editor-editform--rendered-not-visible': notVisible,
30+
};
2531

26-
// The '*-rendered-not-visible` class is used to hide the form when it's not visible
27-
// It will be rendered off screen via css rather than using display: none because
28-
// the form needs to be rendered in order to be submitted
29-
const notVisible = !previewExpanded && (ensureFormRendered || formHasRendered);
30-
const extraClass = {
31-
'element-editor-editform--collapsed': !previewExpanded,
32-
'element-editor-editform--rendered-not-visible': notVisible,
33-
};
34-
35-
return (
36-
<div className="element-editor-content">
37-
{!previewExpanded &&
38-
// Show summary
39-
<SummaryComponent
40-
content={content}
41-
fileUrl={fileUrl}
42-
fileTitle={fileTitle}
43-
broken={broken}
44-
/>
45-
}
46-
{(previewExpanded || ensureFormRendered || formHasRendered) &&
47-
// This <div> is used to stop the "onPointerDown" event from bubbling up to the parent element.
48-
// This is done to prevent thigs like <input> fields from starting element drag and drop sorting
49-
// The "PointerDown" event is added by dnd-kit in ElementList.js
50-
<div onPointerDown={(evt) => evt.stopPropagation()}>
51-
<InlineEditFormComponent
52-
extraClass={extraClass}
53-
onClick={(event) => event.stopPropagation()}
54-
elementId={id}
55-
activeTab={activeTab}
56-
onFormInit={onFormInit}
57-
handleLoadingError={handleLoadingError}
58-
onFormSchemaSubmitResponse={onFormSchemaSubmitResponse}
59-
notVisible={notVisible}
60-
/>
61-
</div>
62-
}
63-
{formDirty &&
64-
<input
65-
type="hidden"
66-
name="change-tracker"
67-
className="element-form-dirty-state"
68-
value="1"
32+
return (
33+
<div className="element-editor-content">
34+
{!previewExpanded &&
35+
// Show summary
36+
<SummaryComponent
37+
content={content}
38+
fileUrl={fileUrl}
39+
fileTitle={fileTitle}
40+
broken={broken}
41+
/>
42+
}
43+
{(previewExpanded || ensureFormRendered || formHasRendered) &&
44+
// This <div> is used to stop the "onPointerDown" event from bubbling up to the parent element.
45+
// This is done to prevent thigs like <input> fields from starting element drag and drop sorting
46+
// The "PointerDown" event is added by dnd-kit in ElementList.js
47+
<div onPointerDown={(evt) => evt.stopPropagation()}>
48+
<InlineEditFormComponent
49+
extraClass={extraClass}
50+
onClick={(event) => event.stopPropagation()}
51+
elementId={id}
52+
activeTab={activeTab}
53+
onFormInit={onFormInit}
54+
handleLoadingError={handleLoadingError}
55+
onFormSchemaSubmitResponse={onFormSchemaSubmitResponse}
56+
notVisible={notVisible}
6957
/>
70-
}
71-
</div>
72-
);
73-
}
74-
}
58+
</div>
59+
}
60+
{formDirty &&
61+
<input
62+
type="hidden"
63+
name="change-tracker"
64+
className="element-form-dirty-state"
65+
value="1"
66+
/>
67+
}
68+
</div>
69+
);
70+
};
7571

7672
Content.propTypes = {
7773
id: PropTypes.number,
@@ -90,9 +86,10 @@ Content.propTypes = {
9086
formDirty: PropTypes.object,
9187
};
9288

93-
Content.defaultProps = {};
89+
// Wrapping export in React.memo() because the old class component extended React.PureComponent
90+
const MemoizedContent = memo(Content);
9491

95-
export { Content as Component };
92+
export { MemoizedContent as Component };
9693

9794
export default compose(
9895
inject(
@@ -102,4 +99,4 @@ export default compose(
10299
}),
103100
() => 'ElementEditor.ElementList.Element'
104101
)
105-
)(Content);
102+
)(MemoizedContent);

client/src/components/ElementEditor/ElementActions.js

Lines changed: 40 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { Component } from 'react';
1+
import React from 'react';
22
import PropTypes from 'prop-types';
33
import { compose } from 'redux';
44
import { DropdownItem } from 'reactstrap';
@@ -11,30 +11,31 @@ import AbstractAction from 'components/ElementActions/AbstractAction';
1111
* Element actions is a dropdown menu containing links to inline editing forms for each
1212
* of the element's primary tabs, as well as operations such as save, publish, archive etc
1313
*/
14-
class ElementActions extends Component {
15-
constructor(props) {
16-
super(props);
17-
this.handleEditTabsClick = this.handleEditTabsClick.bind(this);
18-
}
19-
14+
const ElementActions = ({
15+
children,
16+
type,
17+
id,
18+
activeTab,
19+
editTabs = [],
20+
handleEditTabsClick,
21+
expandable = true,
22+
ActionMenuComponent,
23+
}) => {
2024
/**
2125
* Set the active tab
2226
*
2327
* @param {Object} event
2428
*/
25-
handleEditTabsClick(event) {
26-
const { handleEditTabsClick } = this.props;
29+
const handleEditTabsClickFn = (event) => {
2730
handleEditTabsClick(event.target.name);
28-
}
31+
};
2932

3033
/**
3134
* Render buttons for the edit form tabs that will be a part of the edit form (if they exist)
3235
*
3336
* @returns {HTMLElement[]|null}
3437
*/
35-
renderEditTabs() {
36-
const { editTabs, activeTab, type, expandable } = this.props;
37-
38+
const renderEditTabs = () => {
3839
// Don't render tabs if the block is not expandable or if no tabs are defined
3940
if (type.broken || !expandable || !editTabs || !editTabs.length) {
4041
return null;
@@ -47,59 +48,47 @@ class ElementActions extends Component {
4748
name={name}
4849
title={title}
4950
type={type}
50-
onClick={this.handleEditTabsClick}
51+
onClick={handleEditTabsClickFn}
5152
active={name === activeTab}
5253
/>)
5354
);
54-
}
55+
};
5556

5657
/**
5758
* Renders a divider if there are CMS edit tabs and child actions
5859
*
5960
* @returns {DropdownItem|null}
6061
*/
61-
renderDivider() {
62-
const { children, editTabs, expandable } = this.props;
63-
62+
const renderDivider = () => {
6463
// Don't render divider if the block is not expandable or if no tabs are defined
6564
// or if there's no actions displayed after the tab list
6665
if (!expandable || !editTabs || !editTabs.length || React.Children.count(children) === 0) {
6766
return null;
6867
}
6968

7069
return <DropdownItem divider role="separator" />;
71-
}
70+
};
7271

73-
/**
74-
* If inline editing is enabled, render the "more actions" menu. Injector registrations can
75-
* define HOCs that add action components as children of this component.
76-
*
77-
* @returns {ActionMenuComponent|null}
78-
*/
79-
render() {
80-
const { children, id, ActionMenuComponent } = this.props;
72+
const dropdownToggleClassNames = [
73+
'element-editor-header__actions-toggle',
74+
'btn',
75+
'btn-sm',
76+
'btn--no-text',
77+
];
8178

82-
const dropdownToggleClassNames = [
83-
'element-editor-header__actions-toggle',
84-
'btn',
85-
'btn-sm',
86-
'btn--no-text',
87-
];
88-
89-
return (
90-
<ActionMenuComponent
91-
id={`element-editor-actions-${id}`}
92-
className="element-editor-header__actions-dropdown"
93-
dropdownMenuProps={{ right: true }}
94-
dropdownToggleClassNames={dropdownToggleClassNames}
95-
>
96-
{ this.renderEditTabs() }
97-
{ this.renderDivider() }
98-
{ children }
99-
</ActionMenuComponent>
100-
);
101-
}
102-
}
79+
return (
80+
<ActionMenuComponent
81+
id={`element-editor-actions-${id}`}
82+
className="element-editor-header__actions-dropdown"
83+
dropdownMenuProps={{ right: true }}
84+
dropdownToggleClassNames={dropdownToggleClassNames}
85+
>
86+
{ renderEditTabs() }
87+
{ renderDivider() }
88+
{ children }
89+
</ActionMenuComponent>
90+
);
91+
};
10392

10493
// There's some extra prop types in here for registered transformations to consume
10594
ElementActions.propTypes = {
@@ -114,12 +103,9 @@ ElementActions.propTypes = {
114103
name: PropTypes.string,
115104
})),
116105
handleEditTabsClick: PropTypes.func.isRequired,
117-
expandable: PropTypes.bool
118-
};
119-
120-
ElementActions.defaultProps = {
121-
editTabs: [],
122-
expandable: true
106+
expandable: PropTypes.bool,
107+
children: PropTypes.node,
108+
ActionMenuComponent: PropTypes.elementType.isRequired,
123109
};
124110

125111
export { ElementActions as Component };

0 commit comments

Comments
 (0)