From 1a4a20d0b7d3d4d2a12e516013754ba3c1527226 Mon Sep 17 00:00:00 2001
From: Damian Stasik <920747+damianstasik@users.noreply.github.com>
Date: Sat, 1 Oct 2022 15:28:10 +0200
Subject: [PATCH] refactor: prevent usage of `this.state` inside `setState`
calls
---
.eslintrc.json | 3 +-
.../BrowserCell/BrowserCell.react.js | 2 +-
src/components/Calendar/Calendar.react.js | 12 +-
.../CascadingView/CascadingView.react.js | 2 +-
.../ChromeDatePicker.react.js | 4 +-
.../ColumnsConfiguration.react.js | 6 +-
src/components/DatePicker/DatePicker.react.js | 4 +-
src/components/DateRange/DateRange.react.js | 28 +-
.../DateTimeInput/DateTimeInput.react.js | 4 +-
src/components/Dropdown/Dropdown.react.js | 4 +-
.../ExplorerActiveChartButton.react.js | 14 +-
.../ExplorerMenuButton.react.js | 4 +-
.../ExplorerQueryComposer.react.js | 246 ++++++++++--------
src/components/FlowView/FlowView.react.js | 21 +-
.../GeoPointEditor/GeoPointEditor.react.js | 2 +-
.../MultiSelect/MultiSelect.react.js | 2 +-
.../NumberEditor/NumberEditor.react.js | 2 +-
.../PermissionsDialog.react.js | 134 +++++-----
.../ProtectedFieldsDialog.react.js | 36 +--
.../PushAudiencesBaseRow.react.js | 6 +-
.../SaveButton/SaveButton.example.js | 10 +-
.../SliderWrap/SliderWrap.example.js | 6 +-
.../SuggestionsList/SuggestionsList.react.js | 2 +-
.../Analytics/Explorer/Explorer.react.js | 156 ++++++-----
.../Performance/Performance.react.js | 22 +-
src/dashboard/Data/Browser/Browser.react.js | 122 ++++-----
.../Data/Browser/DataBrowser.react.js | 40 +--
.../Data/Browser/ObjectPickerDialog.react.js | 29 ++-
.../Data/Migration/Migration.react.js | 2 +-
src/dashboard/Push/PushDetails.react.js | 14 +-
src/dashboard/Push/PushIndex.react.js | 6 +-
src/dashboard/Push/PushNew.react.js | 82 +++---
src/dashboard/Settings/SettingsData.react.js | 5 +-
33 files changed, 555 insertions(+), 477 deletions(-)
diff --git a/.eslintrc.json b/.eslintrc.json
index ef6e559e6c..c9053ec7a5 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -21,6 +21,7 @@
"no-console": 0,
"no-case-declarations": 0,
"quotes": ["error", "single"],
- "eol-last": ["error", "always"]
+ "eol-last": ["error", "always"],
+ "react/no-access-state-in-setstate": 1
}
}
diff --git a/src/components/BrowserCell/BrowserCell.react.js b/src/components/BrowserCell/BrowserCell.react.js
index faaa5011db..1774818e8d 100644
--- a/src/components/BrowserCell/BrowserCell.react.js
+++ b/src/components/BrowserCell/BrowserCell.react.js
@@ -172,7 +172,7 @@ export default class BrowserCell extends Component {
classes.push(styles.required);
}
- this.setState({ ...this.state, content, classes })
+ this.setState({ content, classes })
}
componentDidUpdate(prevProps) {
diff --git a/src/components/Calendar/Calendar.react.js b/src/components/Calendar/Calendar.react.js
index 9ae8f8315c..e65764dc67 100644
--- a/src/components/Calendar/Calendar.react.js
+++ b/src/components/Calendar/Calendar.react.js
@@ -35,15 +35,15 @@ export default class Calendar extends React.Component {
}
handlePrev() {
- this.setState({
- currentMonth: prevMonth(this.state.currentMonth)
- });
+ this.setState((prev) => ({
+ currentMonth: prevMonth(prev.currentMonth)
+ }));
}
handleNext() {
- this.setState({
- currentMonth: nextMonth(this.state.currentMonth)
- });
+ this.setState((prev) => ({
+ currentMonth: nextMonth(prev.currentMonth)
+ }));
}
renderMonth() {
diff --git a/src/components/CascadingView/CascadingView.react.js b/src/components/CascadingView/CascadingView.react.js
index 103f5e0ee2..fd03a6892d 100644
--- a/src/components/CascadingView/CascadingView.react.js
+++ b/src/components/CascadingView/CascadingView.react.js
@@ -38,7 +38,7 @@ export default class CascadingView extends React.Component {
this.setState({ expanded: !this.state.expanded })}>
+ onClick={() => this.setState((prev) => ({ expanded: !prev.expanded }))}>
{content}
{expander}
diff --git a/src/components/ChromeDatePicker/ChromeDatePicker.react.js b/src/components/ChromeDatePicker/ChromeDatePicker.react.js
index a607b2f4b1..5ab983484d 100644
--- a/src/components/ChromeDatePicker/ChromeDatePicker.react.js
+++ b/src/components/ChromeDatePicker/ChromeDatePicker.react.js
@@ -30,8 +30,8 @@ export default class ChromeDatePicker extends React.Component {
}
toggle() {
- this.setState(() => {
- if (this.state.open) {
+ this.setState((prev) => {
+ if (prev.open) {
return { open: false };
}
let pos = Position.inWindow(this.wrapRef.current);
diff --git a/src/components/ColumnsConfiguration/ColumnsConfiguration.react.js b/src/components/ColumnsConfiguration/ColumnsConfiguration.react.js
index 45c9389087..475337aa67 100644
--- a/src/components/ColumnsConfiguration/ColumnsConfiguration.react.js
+++ b/src/components/ColumnsConfiguration/ColumnsConfiguration.react.js
@@ -31,9 +31,9 @@ export default class ColumnsConfiguration extends React.Component {
}
toggle() {
- this.setState({
- open: !this.state.open
- })
+ this.setState((prev) => ({
+ open: !prev.open
+ }))
}
showAll() {
diff --git a/src/components/DatePicker/DatePicker.react.js b/src/components/DatePicker/DatePicker.react.js
index 6ae363adf9..3a6820bb1a 100644
--- a/src/components/DatePicker/DatePicker.react.js
+++ b/src/components/DatePicker/DatePicker.react.js
@@ -25,8 +25,8 @@ export default class DatePicker extends React.Component {
}
toggle() {
- this.setState(() => {
- if (this.state.open) {
+ this.setState((prev) => {
+ if (prev.open) {
return { open: false };
}
return {
diff --git a/src/components/DateRange/DateRange.react.js b/src/components/DateRange/DateRange.react.js
index 555b7eb6c8..ab7ee810c6 100644
--- a/src/components/DateRange/DateRange.react.js
+++ b/src/components/DateRange/DateRange.react.js
@@ -36,8 +36,8 @@ export default class DateRange extends React.Component {
}
toggle() {
- this.setState(() => {
- if (this.state.open) {
+ this.setState((prev) => {
+ if (prev.open) {
return { open: false };
}
let pos = Position.inWindow(this.wrapRef.current);
@@ -52,19 +52,23 @@ export default class DateRange extends React.Component {
}
setStart(start) {
- let end = this.state.end;
- if (start > end) {
- end = daysFrom(start, 1);
- }
- this.setState({ start, end });
+ this.setState((prev) => {
+ let end = prev.end;
+ if (start > end) {
+ end = daysFrom(start, 1);
+ }
+ return { start, end };
+ });
}
setEnd(end) {
- let start = this.state.start;
- if (start > end) {
- start = daysFrom(end, -1);
- }
- this.setState({ start, end });
+ this.setState((prev) => {
+ let start = prev.start;
+ if (start > end) {
+ start = daysFrom(end, -1);
+ }
+ return { start, end };
+ });
}
close() {
diff --git a/src/components/DateTimeInput/DateTimeInput.react.js b/src/components/DateTimeInput/DateTimeInput.react.js
index 5c66e9c177..f3422280dc 100644
--- a/src/components/DateTimeInput/DateTimeInput.react.js
+++ b/src/components/DateTimeInput/DateTimeInput.react.js
@@ -25,8 +25,8 @@ export default class DateTimeInput extends React.Component {
}
toggle() {
- this.setState(() => {
- if (this.state.open) {
+ this.setState((prev) => {
+ if (prev.open) {
return { open: false };
}
let node = this.inputRef.current;
diff --git a/src/components/Dropdown/Dropdown.react.js b/src/components/Dropdown/Dropdown.react.js
index 3f444767f9..a9c1dfd2ab 100644
--- a/src/components/Dropdown/Dropdown.react.js
+++ b/src/components/Dropdown/Dropdown.react.js
@@ -25,8 +25,8 @@ export default class Dropdown extends React.Component {
}
toggle() {
- this.setState(() => {
- if (this.state.open) {
+ this.setState((prev) => {
+ if (prev.open) {
return { open: false };
}
let pos = Position.inDocument(this.dropdownRef.current);
diff --git a/src/components/ExplorerActiveChartButton/ExplorerActiveChartButton.react.js b/src/components/ExplorerActiveChartButton/ExplorerActiveChartButton.react.js
index 51930881be..160b4cc5d7 100644
--- a/src/components/ExplorerActiveChartButton/ExplorerActiveChartButton.react.js
+++ b/src/components/ExplorerActiveChartButton/ExplorerActiveChartButton.react.js
@@ -30,10 +30,10 @@ export default class ExplorerActiveChartButton extends React.Component {
}
handleCheckbox() {
- let nextActiveState = !this.state.active;
- this.props.onToggle(nextActiveState);
- this.setState({
- active: nextActiveState
+ this.setState((prev) => ({
+ active: !prev.active
+ }), () => {
+ this.props.onToggle(this.state.active);
});
}
@@ -67,11 +67,11 @@ export default class ExplorerActiveChartButton extends React.Component {
position.x += this.wrapRef.current.clientWidth;
align = Directions.RIGHT;
}
- this.setState({
- open: !this.state.open,
+ this.setState((prev) => ({
+ open: !prev.open,
position,
align
- });
+ }));
}} />
);
}
diff --git a/src/components/ExplorerMenuButton/ExplorerMenuButton.react.js b/src/components/ExplorerMenuButton/ExplorerMenuButton.react.js
index 254bb5bdb2..dea82c04f3 100644
--- a/src/components/ExplorerMenuButton/ExplorerMenuButton.react.js
+++ b/src/components/ExplorerMenuButton/ExplorerMenuButton.react.js
@@ -28,8 +28,8 @@ export default class ExplorerMenuButton extends React.Component {
}
toggle() {
- this.setState(() => {
- if (this.state.currentView) {
+ this.setState((prev) => {
+ if (prev.currentView) {
return { currentView: null };
}
let position = Position.inDocument(this.wrapRef.current);
diff --git a/src/components/ExplorerQueryComposer/ExplorerQueryComposer.react.js b/src/components/ExplorerQueryComposer/ExplorerQueryComposer.react.js
index 046ae0f232..5f68f08ea7 100644
--- a/src/components/ExplorerQueryComposer/ExplorerQueryComposer.react.js
+++ b/src/components/ExplorerQueryComposer/ExplorerQueryComposer.react.js
@@ -192,10 +192,10 @@ export default class ExplorerQueryComposer extends React.Component {
}
toggleEditing() {
- this.setState({
- editing: !this.state.editing,
- newName: this.state.name
- });
+ this.setState((prev) => ({
+ editing: !prev.editing,
+ newName: prev.name
+ }));
}
handleSave() {
@@ -213,11 +213,11 @@ export default class ExplorerQueryComposer extends React.Component {
objectId: query.objectId
});
- this.setState({
+ this.setState((prev) => ({
editing: false,
- name: this.state.newName,
- isSaved: !!this.state.newName
- });
+ name: prev.newName,
+ isSaved: !!prev.newName
+ }));
}
handleNameChange(e) {
@@ -225,39 +225,39 @@ export default class ExplorerQueryComposer extends React.Component {
}
handleAddAggregate() {
- this.setState({
- aggregates: this.state.aggregates.concat([{
+ this.setState((prev) => ({
+ aggregates: prev.aggregates.concat([{
op: AGGREGATE_TYPE_LABELS[0],
- col: FIELD_LABELS[this.state.source][0]
+ col: FIELD_LABELS[prev.source][0]
}])
- });
+ }));
}
handleAddGroup() {
- this.setState({
- groups: this.state.groups.concat([
- FIELD_LABELS[this.state.source][0]
+ this.setState((prev) => ({
+ groups: prev.groups.concat([
+ FIELD_LABELS[prev.source][0]
])
- });
+ }));
}
handleAddFilter() {
- this.setState({
- filters: this.state.filters.concat([{
+ this.setState((prev) => ({
+ filters: prev.filters.concat([{
op: '$eq',
- col: FIELD_LABELS[this.state.source][0],
+ col: FIELD_LABELS[prev.source][0],
val: null
}])
- });
+ }));
}
handleAddOrder() {
- this.setState({
- orders: this.state.orders.concat([{
+ this.setState((prev) => ({
+ orders: prev.orders.concat([{
col: null,
asc: ORDER_LABELS[0]
}])
- });
+ }));
}
handleSourceChange(newSource) {
@@ -269,8 +269,10 @@ export default class ExplorerQueryComposer extends React.Component {
}
removeAdditionalQuery(stateKey, index) {
- this.state[stateKey].splice(index, 1);
- this.setState({ [stateKey]: this.state[stateKey] });
+ this.setState((prev) => {
+ prev[stateKey].splice(index, 1);
+ return { [stateKey]: prev[stateKey] };
+ });
}
renderAggregate(aggregate, index=0) {
@@ -296,12 +298,14 @@ export default class ExplorerQueryComposer extends React.Component {
value={aggregate.op}
options={AGGREGATE_TYPE_LABELS}
onChange={(val) => {
- let aggregates = this.state.aggregates;
- aggregates[index] = {
- op: val,
- col: FIELD_LABELS[this.state.source][0]
- };
- this.setState({ aggregates });
+ this.setState((prev) => {
+ let aggregates = prev.aggregates;
+ aggregates[index] = {
+ op: val,
+ col: FIELD_LABELS[prev.source][0]
+ };
+ return { aggregates };
+ });
}}
color='blue'
width='100%' />
@@ -322,9 +326,11 @@ export default class ExplorerQueryComposer extends React.Component {
}
})}
onChange={(val) => {
- let aggregates = this.state.aggregates;
- aggregates[index].col = val;
- this.setState({ aggregates });
+ this.setState((prev) => {
+ let aggregates = prev.aggregates;
+ aggregates[index].col = val;
+ return { aggregates };
+ });
}}
color='blue'
width='100%' />
@@ -358,9 +364,11 @@ export default class ExplorerQueryComposer extends React.Component {
value={grouping}
options={specialGroup ? REQUIRED_GROUPING_LABELS : FIELD_LABELS[this.state.source]}
onChange={(val) => {
- let groups = this.state.groups;
- groups[index] = val;
- this.setState({ groups });
+ this.setState((prev) => {
+ let groups = prev.groups;
+ groups[index] = val;
+ return { groups };
+ });
}}
color='blue'
width='100%' />
@@ -389,30 +397,34 @@ export default class ExplorerQueryComposer extends React.Component {
value={Constraints[filter.json_scalar_op].name}
options={FieldConstraints['JSONValue'].map((c) => Constraints[c].name)}
onChange={(val) => {
- let filters = this.state.filters;
- filters[index] = {
- col: filter.col,
- op: filter.op,
- json_path: filter.json_path,
- json_scalar_op: constraintLookup[val],
- val: filter.val
- };
- this.setState({ filters });
+ this.setState((prev) => {
+ let filters = prev.filters;
+ filters[index] = {
+ col: filter.col,
+ op: filter.op,
+ json_path: filter.json_path,
+ json_scalar_op: constraintLookup[val],
+ val: filter.val
+ };
+ return { filters };
+ });
}} />
diff --git a/src/components/MultiSelect/MultiSelect.react.js b/src/components/MultiSelect/MultiSelect.react.js
index 2e3dcb1758..177d8b8f36 100644
--- a/src/components/MultiSelect/MultiSelect.react.js
+++ b/src/components/MultiSelect/MultiSelect.react.js
@@ -55,7 +55,7 @@ export default class MultiSelect extends React.Component {
toggle() {
this.setPosition();
- this.setState({ open: !this.state.open });
+ this.setState((prev) => ({ open: !prev.open }));
}
close(e) {
diff --git a/src/components/NumberEditor/NumberEditor.react.js b/src/components/NumberEditor/NumberEditor.react.js
index 0a63275272..43679d9bdd 100644
--- a/src/components/NumberEditor/NumberEditor.react.js
+++ b/src/components/NumberEditor/NumberEditor.react.js
@@ -60,7 +60,7 @@ export default class NumberEditor extends React.Component {
render() {
let onChange = (e) => {
let value = e.target.value;
- this.setState({ value: validateNumeric(value) ? value : this.state.value });
+ this.setState((prev) => ({ value: validateNumeric(value) ? value : prev.value }));
};
return (
diff --git a/src/components/PermissionsDialog/PermissionsDialog.react.js b/src/components/PermissionsDialog/PermissionsDialog.react.js
index b4d749494f..1c11cf34be 100644
--- a/src/components/PermissionsDialog/PermissionsDialog.react.js
+++ b/src/components/PermissionsDialog/PermissionsDialog.react.js
@@ -761,11 +761,6 @@ export default class PermissionsDialog extends React.Component {
let id, name, key, newEntry;
- let nextKeys;
- let nextEntryTypes;
- let nextPerms = this.state.perms;
- let nextPointerPerms = this.state.pointerPerms;
-
if (next.user || next.role) {
id = next.user ? next.user.id : next.role.id;
name = next.user ? next.user.get('username') : next.role.getName();
@@ -791,46 +786,48 @@ export default class PermissionsDialog extends React.Component {
});
}
- // create new permissions
- if (next.pointer) {
- if (this.props.advanced) {
- nextPointerPerms = nextPointerPerms.setIn([entry, 'get'], true)
- nextPointerPerms = nextPointerPerms.setIn([entry, 'find'], true)
- nextPointerPerms = nextPointerPerms.setIn([entry, 'count'], true)
- nextPointerPerms = nextPointerPerms.setIn([entry, 'create'], true)
- nextPointerPerms = nextPointerPerms.setIn([entry, 'update'], true)
- nextPointerPerms = nextPointerPerms.setIn([entry, 'delete'], true)
- nextPointerPerms = nextPointerPerms.setIn([entry, 'addField'], true)
- } else {
- nextPointerPerms = nextPointerPerms.setIn([entry, 'read'], true)
- nextPointerPerms = nextPointerPerms.setIn([entry, 'write'], true)
- }
- } else {
- if (this.props.advanced) {
- nextPerms = nextPerms.setIn(['get', key], true);
- nextPerms = nextPerms.setIn(['find', key], true);
- nextPerms = nextPerms.setIn(['count', key], true);
- nextPerms = nextPerms.setIn(['create', key], true);
- nextPerms = nextPerms.setIn(['update', key], true);
- nextPerms = nextPerms.setIn(['delete', key], true);
- nextPerms = nextPerms.setIn(['addField', key], true);
- } else {
- nextPerms = nextPerms.setIn(['read', key], true);
- nextPerms = nextPerms.setIn(['write', key], true);
- }
- }
-
- nextKeys = this.state.newKeys.concat([key]);
- nextEntryTypes = this.state.entryTypes.set(key, newEntry);
-
return this.setState(
- {
- perms: nextPerms,
- pointerPerms: nextPointerPerms,
- newKeys: nextKeys,
- entryTypes: nextEntryTypes,
- newEntry: '',
- entryError: null
+ (prev) => {
+ let nextPerms = prev.perms;
+ let nextPointerPerms = prev.pointerPerms;
+
+ // create new permissions
+ if (next.pointer) {
+ if (this.props.advanced) {
+ nextPointerPerms = nextPointerPerms.setIn([entry, 'get'], true)
+ nextPointerPerms = nextPointerPerms.setIn([entry, 'find'], true)
+ nextPointerPerms = nextPointerPerms.setIn([entry, 'count'], true)
+ nextPointerPerms = nextPointerPerms.setIn([entry, 'create'], true)
+ nextPointerPerms = nextPointerPerms.setIn([entry, 'update'], true)
+ nextPointerPerms = nextPointerPerms.setIn([entry, 'delete'], true)
+ nextPointerPerms = nextPointerPerms.setIn([entry, 'addField'], true)
+ } else {
+ nextPointerPerms = nextPointerPerms.setIn([entry, 'read'], true)
+ nextPointerPerms = nextPointerPerms.setIn([entry, 'write'], true)
+ }
+ } else {
+ if (this.props.advanced) {
+ nextPerms = nextPerms.setIn(['get', key], true);
+ nextPerms = nextPerms.setIn(['find', key], true);
+ nextPerms = nextPerms.setIn(['count', key], true);
+ nextPerms = nextPerms.setIn(['create', key], true);
+ nextPerms = nextPerms.setIn(['update', key], true);
+ nextPerms = nextPerms.setIn(['delete', key], true);
+ nextPerms = nextPerms.setIn(['addField', key], true);
+ } else {
+ nextPerms = nextPerms.setIn(['read', key], true);
+ nextPerms = nextPerms.setIn(['write', key], true);
+ }
+ }
+
+ return {
+ perms: nextPerms,
+ pointerPerms: nextPointerPerms,
+ newKeys: prev.newKeys.concat([key]),
+ entryTypes: prev.entryTypes.set(key, newEntry),
+ newEntry: '',
+ entryError: null
+ }
},
() => this.refEntry.current.resetInput()
);
@@ -855,20 +852,25 @@ export default class PermissionsDialog extends React.Component {
if (isPointer) {
let index = this.state.pointers.indexOf(key);
if (index > -1) {
- let filtered = this.state.pointers.concat([]);
- filtered.splice(index, 1);
- return this.setState({
- pointers: filtered,
- pointerPerms: this.state.pointerPerms.delete(key)
+ return this.setState((prev) => {
+ let filtered = prev.pointers.concat([]);
+ filtered.splice(index, 1);
+
+ return {
+ pointers: filtered,
+ pointerPerms: prev.pointerPerms.delete(key)
+ };
});
}
index = this.state.newKeys.indexOf(key);
if (index > -1) {
- let filtered = this.state.newKeys.concat([]);
- filtered.splice(index, 1);
- return this.setState({
- newKeys: filtered,
- pointerPerms: this.state.pointerPerms.delete(key)
+ return this.setState((prev) => {
+ let filtered = prev.newKeys.concat([]);
+ filtered.splice(index, 1);
+ return {
+ newKeys: filtered,
+ pointerPerms: prev.pointerPerms.delete(key)
+ };
});
}
} else {
@@ -887,20 +889,24 @@ export default class PermissionsDialog extends React.Component {
newPerms = newPerms.deleteIn(['read', key]).deleteIn(['write', key]);
}
if (index > -1) {
- let filtered = this.state.keys.concat([]);
- filtered.splice(index, 1);
- return this.setState({
- keys: filtered,
- perms: newPerms
+ return this.setState((prev) => {
+ let filtered = prev.keys.concat([]);
+ filtered.splice(index, 1);
+ return {
+ keys: filtered,
+ perms: newPerms
+ };
});
}
index = this.state.newKeys.indexOf(key);
if (index > -1) {
- let filtered = this.state.newKeys.concat([]);
- filtered.splice(index, 1);
- return this.setState({
- newKeys: filtered,
- perms: newPerms
+ return this.setState((prev) => {
+ let filtered = prev.newKeys.concat([]);
+ filtered.splice(index, 1);
+ return {
+ newKeys: filtered,
+ perms: newPerms
+ };
});
}
}
diff --git a/src/components/ProtectedFieldsDialog/ProtectedFieldsDialog.react.js b/src/components/ProtectedFieldsDialog/ProtectedFieldsDialog.react.js
index b0f062b216..772f287812 100644
--- a/src/components/ProtectedFieldsDialog/ProtectedFieldsDialog.react.js
+++ b/src/components/ProtectedFieldsDialog/ProtectedFieldsDialog.react.js
@@ -139,17 +139,13 @@ export default class ProtectedFieldsDialog extends React.Component {
});
}
- let nextKeys = this.state.newKeys.concat([key]);
- let nextFields = this.state.protectedFields.set(key, []);
- let nextEntryTypes = this.state.entryTypes.set(key, newEntry);
-
- return this.setState(
- {
- entryTypes: nextEntryTypes,
- protectedFields: nextFields,
- newKeys: nextKeys,
+ return this.setState((prev) =>
+ ({
+ entryTypes: prev.entryTypes.set(key, newEntry),
+ protectedFields: prev.protectedFields.set(key, []),
+ newKeys: prev.newKeys.concat([key]),
entryError: null
- },
+ }),
this.refEntry.current.resetInput()
);
}
@@ -171,18 +167,14 @@ export default class ProtectedFieldsDialog extends React.Component {
}
deleteRow(key) {
- // remove from proectedFields
- let protectedFields = this.state.protectedFields.delete(key);
-
- // also remove from local state
- let keys = this.state.keys.filter(k => k !== key);
- let newKeys = this.state.newKeys.filter(k => k !== key);
-
- return this.setState({
- protectedFields,
- newKeys,
- keys
- });
+ return this.setState((prev) => ({
+ // remove from protectedFields
+ protectedFields: prev.protectedFields.delete(key),
+
+ // also remove from local state
+ keys: prev.keys.filter(k => k !== key),
+ newKeys: prev.newKeys.filter(k => k !== key),
+ }));
}
outputPerms() {
diff --git a/src/components/PushAudiencesSelector/PushAudiencesBaseRow.react.js b/src/components/PushAudiencesSelector/PushAudiencesBaseRow.react.js
index 5b00f94080..8a698ec917 100644
--- a/src/components/PushAudiencesSelector/PushAudiencesBaseRow.react.js
+++ b/src/components/PushAudiencesSelector/PushAudiencesBaseRow.react.js
@@ -25,9 +25,9 @@ export default class PushAudiencesBaseRow extends React.Component {
handleDetailsToggle(query, schema, evt) {
evt.preventDefault();
- this.setState({
- expandedView : !this.state.expandedView
- });
+ this.setState((prev) => ({
+ expandedView : !prev.expandedView
+ }));
}
fetchPushSubscriberCount(context) {
diff --git a/src/components/SaveButton/SaveButton.example.js b/src/components/SaveButton/SaveButton.example.js
index f7e55af774..eec59703be 100644
--- a/src/components/SaveButton/SaveButton.example.js
+++ b/src/components/SaveButton/SaveButton.example.js
@@ -23,10 +23,16 @@ class SaveDemo extends React.Component {
handleClick() {
this.setState({ saveState: SaveButton.States.SAVING });
setTimeout(() => {
- let next = this.state.nextState === SaveButton.States.SUCCEEDED ?
+ this.setState((prev) => {
+ let next = prev.nextState === SaveButton.States.SUCCEEDED ?
SaveButton.States.FAILED :
SaveButton.States.SUCCEEDED;
- this.setState({ saveState: this.state.nextState, nextState: next });
+
+ return {
+ saveState: prev.nextState,
+ nextState: next
+ };
+ });
setTimeout(() => {
this.setState({ saveState: SaveButton.States.WAITING });
diff --git a/src/components/SliderWrap/SliderWrap.example.js b/src/components/SliderWrap/SliderWrap.example.js
index b03c0278ce..e3cec88a02 100644
--- a/src/components/SliderWrap/SliderWrap.example.js
+++ b/src/components/SliderWrap/SliderWrap.example.js
@@ -26,9 +26,9 @@ class Toggler extends React.Component {
}
toggle() {
- this.setState({
- expanded: !this.state.expanded
- });
+ this.setState((prev) => ({
+ expanded: !prev.expanded
+ }));
}
render() {
diff --git a/src/components/SuggestionsList/SuggestionsList.react.js b/src/components/SuggestionsList/SuggestionsList.react.js
index 6b0268e404..ab4288bc0a 100644
--- a/src/components/SuggestionsList/SuggestionsList.react.js
+++ b/src/components/SuggestionsList/SuggestionsList.react.js
@@ -23,7 +23,7 @@ export default class Suggestion extends React.Component {
toggle() {
this.setPosition();
- this.setState({ open: !this.state.open });
+ this.setState((prev) => ({ open: !prev.open }));
}
setPosition(position) {
diff --git a/src/dashboard/Analytics/Explorer/Explorer.react.js b/src/dashboard/Analytics/Explorer/Explorer.react.js
index 4134412ff3..2e7db2aa54 100644
--- a/src/dashboard/Analytics/Explorer/Explorer.react.js
+++ b/src/dashboard/Analytics/Explorer/Explorer.react.js
@@ -99,52 +99,58 @@ class Explorer extends DashboardView {
}
handleQueryToggle(index, active) {
- let activeQueries = this.state.activeQueries;
- activeQueries[index].enabled = active;
- this.setState({ activeQueries: activeQueries });
+ this.setState((prev) => {
+ let activeQueries = prev.activeQueries;
+ activeQueries[index].enabled = active;
+ return { activeQueries };
+ });
}
handleQuerySave(query) {
- // Push new save result
- let activeQueries = this.state.activeQueries;
- let existingQueryIndex = activeQueries.findIndex((activeQuery) => {
- if (query.localId) {
- return query.localId === activeQuery.localId;
- }
- if (query.objectId) {
- return query.objectId === activeQuery.objectId;
- }
- return false;
- });
-
- query.enabled = true;
- if (existingQueryIndex === -1) {
- // Push new
- // Make random ID
- query.localId = 'query' + new Date().getTime();
- activeQueries.push(query);
- if (!query.name) {
- query.name = buildFriendlyName(query);
+ // Update the state to trigger rendering pipeline.
+ this.setState((prev) => {
+ // Push new save result
+ let activeQueries = prev.activeQueries;
+ let existingQueryIndex = activeQueries.findIndex((activeQuery) => {
+ if (query.localId) {
+ return query.localId === activeQuery.localId;
+ }
+ if (query.objectId) {
+ return query.objectId === activeQuery.objectId;
+ }
+ return false;
+ });
+
+ query.enabled = true;
+ if (existingQueryIndex === -1) {
+ // Push new
+ // Make random ID
+ query.localId = 'query' + new Date().getTime();
+ activeQueries.push(query);
+ if (!query.name) {
+ query.name = buildFriendlyName(query);
+ }
+ } else {
+ // Update
+ activeQueries[existingQueryIndex] = query;
}
- } else {
- // Update
- activeQueries[existingQueryIndex] = query;
- }
- // Update the state to trigger rendering pipeline.
- this.setState({
- activeQueries,
- mutated: true
+ return {
+ activeQueries,
+ mutated: true
+ };
});
}
handleQuerySelect(query) {
- let activeQueries = this.state.activeQueries;
- query.enabled = true;
- activeQueries.push(query);
- this.setState({
- activeQueries,
- mutated: true
+ this.setState((prev) => {
+ let activeQueries = prev.activeQueries;
+ query.enabled = true;
+ activeQueries.push(query);
+ return {
+ activeQueries,
+ mutated: true
+ };
});
}
@@ -173,46 +179,50 @@ class Explorer extends DashboardView {
let abortableRequest = this.context.getAnalyticsTimeSeries(payload);
promise = abortableRequest.promise.then((result) => {
- let activeQueries = this.state.activeQueries;
- activeQueries[i].result = result.map((point) => (
- [Parse._decode('date', point[0]).getTime(), point[1]]
- ));
- this.setState({ activeQueries });
+ this.setState((prev) => {
+ let activeQueries = prev.activeQueries;
+ activeQueries[i].result = result.map((point) => (
+ [Parse._decode('date', point[0]).getTime(), point[1]]
+ ));
+ return { activeQueries };
+ });
});
xhr = abortableRequest.xhr;
} else {
// Custom query
let payload = this.buildCustomQueryPayload(query);
promise = this.props.customQueries.dispatch(ActionTypes.FETCH, payload).then(() => {
- let activeQueries = this.state.activeQueries;
- // Update the result based on store in background.
- let customQueries = this.getCustomQueriesFromProps(this.props);
- activeQueries = activeQueries.map((query) => {
- let serverResult = null;
- if (query.objectId) {
- // We have predefined custom query.
- serverResult = customQueries.find((customQuery) => {
- return customQuery.objectId === query.objectId;
- });
- } else if (query.localId) {
- // We're in the middle of custom query creation.
- serverResult = customQueries.find((customQuery) => {
- return customQuery.localId === query.localId;
- });
- }
- // If we can't find it in the result, let's use the old one.
- if (!serverResult) {
- serverResult = query;
- }
+ // Trigger rendering pipeline
+ this.setState((prev) => {
+ let activeQueries = prev.activeQueries;
+ // Update the result based on store in background.
+ let customQueries = this.getCustomQueriesFromProps(this.props);
+ activeQueries = activeQueries.map((query) => {
+ let serverResult = null;
+ if (query.objectId) {
+ // We have predefined custom query.
+ serverResult = customQueries.find((customQuery) => {
+ return customQuery.objectId === query.objectId;
+ });
+ } else if (query.localId) {
+ // We're in the middle of custom query creation.
+ serverResult = customQueries.find((customQuery) => {
+ return customQuery.localId === query.localId;
+ });
+ }
+ // If we can't find it in the result, let's use the old one.
+ if (!serverResult) {
+ serverResult = query;
+ }
+
+ return {
+ ...query,
+ result: serverResult.result
+ };
+ });
- return {
- ...query,
- result: serverResult.result
- };
+ return { activeQueries };
});
-
- // Trigger rendering pipeline
- this.setState({ activeQueries });
});
}
@@ -356,9 +366,11 @@ class Explorer extends DashboardView {
onSave={this.handleQuerySave.bind(this)}
onToggle={this.handleQueryToggle.bind(this, i)}
onDismiss={() => {
- let activeQueries = this.state.activeQueries;
- activeQueries.splice(i, 1);
- this.setState({ activeQueries, mutated: true });
+ this.setState((prev) => {
+ let activeQueries = prev.activeQueries;
+ activeQueries.splice(i, 1);
+ return { activeQueries, mutated: true };
+ });
}}
isTimeSeries={isTimeSeries}
query={query}
diff --git a/src/dashboard/Analytics/Performance/Performance.react.js b/src/dashboard/Analytics/Performance/Performance.react.js
index b515f4c1ac..344b278ef1 100644
--- a/src/dashboard/Analytics/Performance/Performance.react.js
+++ b/src/dashboard/Analytics/Performance/Performance.react.js
@@ -116,9 +116,14 @@ export default class Performance extends DashboardView {
}
handleQueryToggle(index, active) {
- let activeQueries = this.state.activeQueries;
- activeQueries[index] = active;
- this.setState({ activeQueries: activeQueries });
+ this.setState((prev) => {
+ let activeQueries = prev.activeQueries;
+ activeQueries[index] = active;
+
+ return {
+ activeQueries
+ };
+ });
}
handleRunQuery(app) {
@@ -135,10 +140,13 @@ export default class Performance extends DashboardView {
});
promise = promise.then((result) => {
- let performanceData = this.state.performanceData;
- performanceData[index] = result;
- this.setState({
- performanceData: performanceData
+ this.setState((prev) => {
+ let performanceData = prev.performanceData;
+ performanceData[index] = result;
+
+ return {
+ performanceData
+ };
});
});
diff --git a/src/dashboard/Data/Browser/Browser.react.js b/src/dashboard/Data/Browser/Browser.react.js
index 23702a7419..0edf2c277e 100644
--- a/src/dashboard/Data/Browser/Browser.react.js
+++ b/src/dashboard/Data/Browser/Browser.react.js
@@ -326,14 +326,13 @@ class Browser extends DashboardView {
});
}
- newColumn(payload, required) {
+ newColumn(name, payload, required) {
return this.props.schema.dispatch(ActionTypes.ADD_COLUMN, payload)
.then(() => {
if (required) {
- let requiredCols = [...this.state.requiredColumnFields, name];
- this.setState({
- requiredColumnFields: requiredCols
- });
+ this.setState((prev) => ({
+ requiredColumnFields: [...prev.requiredColumnFields, name]
+ }));
}
})
.catch((err) => {
@@ -350,7 +349,7 @@ class Browser extends DashboardView {
required,
defaultValue
};
- this.newColumn(payload, required).finally(() => {
+ this.newColumn(name, payload, required).finally(() => {
this.setState({ showAddColumnDialog: false, keepAddingCols: false });
});
}
@@ -364,7 +363,7 @@ class Browser extends DashboardView {
required,
defaultValue
};
- this.newColumn(payload, required).finally(() => {
+ this.newColumn(name, payload, required).finally(() => {
this.setState({ showAddColumnDialog: false, keepAddingCols: false });
this.setState({ showAddColumnDialog: true, keepAddingCols: true });
});
@@ -372,12 +371,11 @@ class Browser extends DashboardView {
addRow() {
if (!this.state.newObject) {
- const relation = this.state.relation;
- this.setState({
- newObject: (relation ?
- new Parse.Object(relation.targetClassName)
+ this.setState((prev) => ({
+ newObject: (prev.relation ?
+ new Parse.Object(prev.relation.targetClassName)
: new Parse.Object(this.props.params.className) ),
- });
+ }));
}
}
@@ -454,15 +452,15 @@ class Browser extends DashboardView {
const targetClassName = relation.targetClassName;
parent.save(null, { useMasterKey }).then(
() => {
- this.setState({
+ this.setState((prev) => ({
newObject: null,
- data: [obj, ...this.state.data],
- relationCount: this.state.relationCount + 1,
+ data: [obj, ...prev.data],
+ relationCount: prev.relationCount + 1,
counts: {
- ...this.state.counts,
- [targetClassName]: this.state.counts[targetClassName] + 1
+ ...prev.counts,
+ [targetClassName]: prev.counts[targetClassName] + 1
}
- });
+ }));
},
error => {
let msg = typeof error === 'string' ? error : error.message;
@@ -470,7 +468,7 @@ class Browser extends DashboardView {
msg = msg[0].toUpperCase() + msg.substr(1);
}
obj.revert();
- this.setState({ data: this.state.data });
+ this.setState((prev) => ({ data: prev.data }));
this.showNote(msg, true);
}
);
@@ -710,17 +708,21 @@ class Browser extends DashboardView {
async fetchData(source, filters = new List()) {
const data = await this.fetchParseData(source, filters);
- var filteredCounts = { ...this.state.filteredCounts };
- if (filters.size > 0) {
- if (this.state.isUnique) {
- filteredCounts[source] = data.length;
+ const count = await this.fetchParseDataCount(source, filters);
+
+ this.setState((prev) => {
+ var filteredCounts = { ...prev.filteredCounts };
+ if (filters.size > 0) {
+ if (prev.isUnique) {
+ filteredCounts[source] = data.length;
+ } else {
+ filteredCounts[source] = count;
+ }
} else {
- filteredCounts[source] = await this.fetchParseDataCount(source, filters);
+ delete filteredCounts[source];
}
- } else {
- delete filteredCounts[source];
- }
- this.setState({ data: data, filters, lastMax: MAX_ROWS_FETCHED , filteredCounts: filteredCounts});
+ return { data: data, filters, lastMax: MAX_ROWS_FETCHED , filteredCounts: filteredCounts};
+ });
}
async fetchRelation(relation, filters = new List()) {
@@ -790,7 +792,7 @@ class Browser extends DashboardView {
}));
}
});
- this.setState({ lastMax: this.state.lastMax + MAX_ROWS_FETCHED });
+ this.setState((prev) => ({ lastMax: prev.lastMax + MAX_ROWS_FETCHED }));
}
updateFilters(filters) {
@@ -896,11 +898,13 @@ class Browser extends DashboardView {
return;
}
if (isEditCloneObj) {
- const editObjIndex = row + (this.state.editCloneRows.length + 1);
- let cloneRows = [...this.state.editCloneRows];
- cloneRows.splice(editObjIndex, 1, obj);
- this.setState({
- editCloneRows: cloneRows
+ this.setState((prev) => {
+ const editObjIndex = row + (prev.editCloneRows.length + 1);
+ let cloneRows = [...prev.editCloneRows];
+ cloneRows.splice(editObjIndex, 1, obj);
+ return {
+ editCloneRows: cloneRows
+ };
});
return;
}
@@ -920,25 +924,25 @@ class Browser extends DashboardView {
parentRelation.add(obj);
const targetClassName = relation.targetClassName;
parent.save(null, { useMasterKey: true }).then(() => {
- this.setState({
+ this.setState((prev) => ({
newObject: null,
data: [
obj,
- ...this.state.data,
+ ...prev.data,
],
- relationCount: this.state.relationCount + 1,
+ relationCount: prev.relationCount + 1,
counts: {
- ...this.state.counts,
- [targetClassName]: this.state.counts[targetClassName] + 1,
+ ...prev.counts,
+ [targetClassName]: prev.counts[targetClassName] + 1,
},
- });
+ }));
}, (error) => {
let msg = typeof error === 'string' ? error : error.message;
if (msg) {
msg = msg[0].toUpperCase() + msg.substr(1);
}
obj.set(attr, prev);
- this.setState({ data: this.state.data });
+ this.setState((prev) => ({ data: prev.data }));
this.showNote(msg, true);
});
} else {
@@ -967,7 +971,7 @@ class Browser extends DashboardView {
}
if (!isNewObject && !isEditCloneObj) {
obj.set(attr, prev);
- this.setState({ data: this.state.data });
+ this.setState((prev) => ({ data: prev.data }));
}
this.showNote(msg, true);
@@ -1015,9 +1019,9 @@ class Browser extends DashboardView {
for (let i = 0; i < indexes.length; i++) {
this.state.data.splice(indexes[i] - i, 1);
}
- this.setState({
- relationCount: this.state.relationCount - toDelete.length,
- });
+ this.setState((prev) => ({
+ relationCount: prev.relationCount - toDelete.length,
+ }));
}
});
} else if (toDelete.length) {
@@ -1137,14 +1141,14 @@ class Browser extends DashboardView {
await parent.save(null, { useMasterKey });
// remove duplication
this.state.data.forEach(origin => objects = objects.filter(object => object.id !== origin.id));
- this.setState({
+ this.setState((prev) => ({
data: [
...objects,
- ...this.state.data,
+ ...prev.data,
],
- relationCount: this.state.relationCount + objects.length,
+ relationCount: prev.relationCount + objects.length,
showAttachRowsDialog: false,
- });
+ }));
}
showAttachSelectedRowsDialog() {
@@ -1206,15 +1210,15 @@ class Browser extends DashboardView {
}
try {
await Parse.Object.saveAll(toClone, { useMasterKey });
- this.setState({
+ this.setState((prev) => ({
selection: {},
- data: [...toClone, ...this.state.data],
+ data: [...toClone, ...prev.data],
showCloneSelectedRowsDialog: false,
counts: {
- ...this.state.counts,
- [className]: this.state.counts[className] + toClone.length
+ ...prev.counts,
+ [className]: prev.counts[className] + toClone.length
}
- });
+ }));
} catch (error) {
//for duplicate, username missing or required field missing errors
if (error.code === 137 || error.code === 200 || error.code === 142) {
@@ -1226,13 +1230,13 @@ class Browser extends DashboardView {
: savedObjects.push(cloneObj);
});
if (savedObjects.length) {
- this.setState({
- data: [...savedObjects, ...this.state.data],
+ this.setState((prev) => ({
+ data: [...savedObjects, ...prev.data],
counts: {
- ...this.state.counts,
- [className]: this.state.counts[className] + savedObjects.length
+ ...prev.counts,
+ [className]: prev.counts[className] + savedObjects.length
}
- });
+ }));
}
this.addEditCloneRows(failedSaveObj);
}
diff --git a/src/dashboard/Data/Browser/DataBrowser.react.js b/src/dashboard/Data/Browser/DataBrowser.react.js
index 962ba7e46c..20aefe12ab 100644
--- a/src/dashboard/Data/Browser/DataBrowser.react.js
+++ b/src/dashboard/Data/Browser/DataBrowser.react.js
@@ -124,11 +124,13 @@ export default class DataBrowser extends React.Component {
* @param {Number} hoverIndex - index of headerbar moved to left of
*/
handleHeaderDragDrop(dragIndex, hoverIndex) {
- const newOrder = [...this.state.order];
- const movedIndex = newOrder.splice(dragIndex, 1);
- newOrder.splice(hoverIndex, 0, movedIndex[0]);
- this.setState({ order: newOrder }, () => {
- this.updatePreferences(newOrder);
+ this.setState((prev) => {
+ const newOrder = [...prev.order];
+ const movedIndex = newOrder.splice(dragIndex, 1);
+ newOrder.splice(hoverIndex, 0, movedIndex[0]);
+ return { order: newOrder };
+ }, () => {
+ this.updatePreferences(this.state.order);
});
}
@@ -199,47 +201,47 @@ export default class DataBrowser extends React.Component {
case 37:
// Left - standalone (move to the next visible column on the left)
// or with ctrl/meta (excel style - move to the first visible column)
- this.setState({
+ this.setState((prev) => ({
current: {
- row: this.state.current.row,
+ row: prev.current.row,
col: (e.ctrlKey || e.metaKey) ? firstVisibleColumnIndex :
this.getNextVisibleColumnIndex(-1, firstVisibleColumnIndex, lastVisibleColumnIndex)
}
- });
+ }));
e.preventDefault();
break;
case 38:
// Up - standalone (move to the previous row)
// or with ctrl/meta (excel style - move to the first row)
- this.setState({
+ this.setState((prev) => ({
current: {
- row: (e.ctrlKey || e.metaKey) ? 0 : Math.max(this.state.current.row - 1, 0),
- col: this.state.current.col
+ row: (e.ctrlKey || e.metaKey) ? 0 : Math.max(prev.current.row - 1, 0),
+ col: prev.current.col
}
- });
+ }));
e.preventDefault();
break;
case 39:
// Right - standalone (move to the next visible column on the right)
// or with ctrl/meta (excel style - move to the last visible column)
- this.setState({
+ this.setState((prev) => ({
current: {
- row: this.state.current.row,
+ row: prev.current.row,
col: (e.ctrlKey || e.metaKey) ? lastVisibleColumnIndex :
this.getNextVisibleColumnIndex(1, firstVisibleColumnIndex, lastVisibleColumnIndex)
}
- });
+ }));
e.preventDefault();
break;
case 40:
// Down - standalone (move to the next row)
// or with ctrl/meta (excel style - move to the last row)
- this.setState({
+ this.setState((prev) => ({
current: {
- row: (e.ctrlKey || e.metaKey) ? this.props.data.length - 1 : Math.min(this.state.current.row + 1, this.props.data.length - 1),
- col: this.state.current.col
+ row: (e.ctrlKey || e.metaKey) ? this.props.data.length - 1 : Math.min(prev.current.row + 1, this.props.data.length - 1),
+ col: prev.current.col
}
- });
+ }));
e.preventDefault();
break;
case 67: // C
diff --git a/src/dashboard/Data/Browser/ObjectPickerDialog.react.js b/src/dashboard/Data/Browser/ObjectPickerDialog.react.js
index f63746a22f..a4312cf7ed 100644
--- a/src/dashboard/Data/Browser/ObjectPickerDialog.react.js
+++ b/src/dashboard/Data/Browser/ObjectPickerDialog.react.js
@@ -83,17 +83,22 @@ export default class ObjectPickerDialog extends React.Component {
async fetchData(source, filters = new List()) {
const data = await this.fetchParseData(source, filters);
- var filteredCounts = { ...this.state.filteredCounts };
- if (filters.size > 0) {
- filteredCounts[source] = await this.fetchParseDataCount(source, filters);
- } else {
- delete filteredCounts[source];
- }
- this.setState({
- data: data,
- filters,
- lastMax: MAX_ROWS_FETCHED,
- filteredCounts: filteredCounts
+ const count = await this.fetchParseDataCount(source, filters);
+
+ this.setState((prev) => {
+ const filteredCounts = { ...prev.filteredCounts };
+ if (filters.size > 0) {
+ filteredCounts[source] = count;
+ } else {
+ delete filteredCounts[source];
+ }
+
+ return {
+ data: data,
+ filters,
+ lastMax: MAX_ROWS_FETCHED,
+ filteredCounts: filteredCounts
+ };
});
}
@@ -182,7 +187,7 @@ export default class ObjectPickerDialog extends React.Component {
}));
}
});
- this.setState({ lastMax: this.state.lastMax + MAX_ROWS_FETCHED });
+ this.setState((prev) => ({ lastMax: prev.lastMax + MAX_ROWS_FETCHED }));
}
async updateFilters(filters) {
diff --git a/src/dashboard/Data/Migration/Migration.react.js b/src/dashboard/Data/Migration/Migration.react.js
index ce14d91678..8139a8c21b 100644
--- a/src/dashboard/Data/Migration/Migration.react.js
+++ b/src/dashboard/Data/Migration/Migration.react.js
@@ -136,7 +136,7 @@ export default class Migration extends DashboardView {
value={this.state.showDetails ? 'Show less details' : 'Show more details'}
primary={true}
width='160px'
- onClick={() => this.setState({showDetails: !this.state.showDetails})} />
+ onClick={() => this.setState((prev) => ({ showDetails: !prev.showDetails }))} />
let showStopMigrationButton = false;
diff --git a/src/dashboard/Push/PushDetails.react.js b/src/dashboard/Push/PushDetails.react.js
index cc022301b7..731c95be0b 100644
--- a/src/dashboard/Push/PushDetails.react.js
+++ b/src/dashboard/Push/PushDetails.react.js
@@ -287,17 +287,17 @@ class PushDetails extends DashboardView {
let chartDataA = formatAnalyticsData(dataA);
let chartDataB = formatAnalyticsData(dataB);
if (chartDataA.length > 0 || chartDataB.length > 0) {
- this.setState({
+ this.setState((prev) => ({
chartData: {
A: {
- color: this.state.groupColorA,
+ color: prev.groupColorA,
points: chartDataA
},
B: {
- color: this.state.groupColorB,
+ color: prev.groupColorB,
points: chartDataB
}
- }});
+ }}));
}
}).finally(() => {
this.setState({ loading: false })
@@ -310,13 +310,13 @@ class PushDetails extends DashboardView {
promise.then((data) => {
let chartData = formatAnalyticsData(data);
if (chartData.length > 0) {
- this.setState({
+ this.setState((prev) => ({
chartData: {
pushes: {
- color: this.state.standardColor,
+ color: prev.standardColor,
points: chartData
}
- }});
+ }}));
}
}).finally(() => {
this.setState({ loading: false })
diff --git a/src/dashboard/Push/PushIndex.react.js b/src/dashboard/Push/PushIndex.react.js
index 5e025fb0b6..0cbdb781ab 100644
--- a/src/dashboard/Push/PushIndex.react.js
+++ b/src/dashboard/Push/PushIndex.react.js
@@ -248,13 +248,13 @@ export default class PushIndex extends DashboardView {
let promise = this.context.fetchPushNotifications(category, page, limit);
promise.then((pushes) => {
- this.setState({
+ this.setState((prev) => ({
paginationInfo: {
has_more: (pushes.length == limit),
page_num: page
},
- pushes: this.state.pushes.concat(pushes),
- });
+ pushes: prev.pushes.concat(pushes),
+ }));
}).finally(() => {
this.setState({
loading: false,
diff --git a/src/dashboard/Push/PushNew.react.js b/src/dashboard/Push/PushNew.react.js
index 3c964a161c..ae03995002 100644
--- a/src/dashboard/Push/PushNew.react.js
+++ b/src/dashboard/Push/PushNew.react.js
@@ -277,8 +277,7 @@ class PushNew extends DashboardView {
track={true}
onChange={(value) => {
setField('exp_size_in_percent', value);
- let recipientCount = Math.floor(value * 0.01 * this.state.deviceCount);
- this.setState({ recipientCount });
+ this.setState((prev) => ({ recipientCount: Math.floor(value * 0.01 * prev.deviceCount) }));
}} />
} />
);
@@ -548,37 +547,35 @@ class PushNew extends DashboardView {
currentLocaleOption={message.locale}
localeOptions = {[message.locale].concat(this.state.availableLocales).sort()}
onClickRemove={(id, currentLocaleOption) => {
- let localizedMessages = this.state.localizedMessages;
- let availableLocales = this.state.availableLocales;
- localizedMessages.splice(id, 1);
- availableLocales.unshift(currentLocaleOption);
- this.setState({
- localizedMessages,
- availableLocales: availableLocales.sort(),
+ this.setState((prev) => {
+ let localizedMessages = prev.localizedMessages;
+ localizedMessages.splice(id, 1);
+
+ let availableLocales = prev.availableLocales;
+ availableLocales.unshift(currentLocaleOption);
+
+ return {
+ localizedMessages,
+ availableLocales: availableLocales.sort(),
+ };
});
}}
deviceCount={this.state.localeDeviceCountMap[message.locale]}
onChangeValue={(id, locale, value) => {
- let localizedMessages = this.state.localizedMessages;
- localizedMessages[id] = {
- locale,
- value
- };
- this.setState({
- localizedMessages,
+ this.setState((prev) => {
+ let localizedMessages = prev.localizedMessages;
+ localizedMessages[id] = {
+ locale,
+ value
+ };
+
+ return {
+ localizedMessages,
+ };
});
setField(`translation[${locale}]`, value);
}}
onChangeLocale={(id, locale, value, prevLocale) => {
- let localizedMessages = this.state.localizedMessages;
- let availableLocales = this.state.availableLocales;
- localizedMessages[id] = {
- locale,
- value
- };
-
- availableLocales.splice(availableLocales.indexOf(locale));
- availableLocales.unshift(prevLocale);
setField(`translation[${prevLocale}]`, null);
let {xhr, promise} = this.context.fetchPushLocaleDeviceCount(fields.audience_id, fields.target, this.state.locales);
@@ -587,9 +584,21 @@ class PushNew extends DashboardView {
});
this.xhrs.push(xhr);
- this.setState({
- localizedMessages,
- availableLocales: availableLocales.sort(),
+ this.setState((prev) => {
+ let localizedMessages = prev.localizedMessages;
+ let availableLocales = prev.availableLocales;
+ localizedMessages[id] = {
+ locale,
+ value
+ };
+
+ availableLocales.splice(availableLocales.indexOf(locale));
+ availableLocales.unshift(prevLocale);
+
+ return {
+ localizedMessages,
+ availableLocales: availableLocales.sort(),
+ }
});
setField(`translation[${locale}]`, value);
}}
@@ -610,13 +619,12 @@ class PushNew extends DashboardView {
disabled={this.state.availableLocales.length === 0}
value={this.state.loadingLocale ? 'Loading locales...' : 'Add a Localization'}
onClick={() => {
- let currentLocale = this.state.availableLocales[0];
- this.setState({
- localizedMessages: this.state.localizedMessages.concat([{
- locale: currentLocale
+ this.setState((prev) => ({
+ localizedMessages: prev.localizedMessages.concat([{
+ locale: prev.availableLocales[0]
}]),
- availableLocales: this.state.availableLocales.slice(1)
- }, () => {
+ availableLocales: prev.availableLocales.slice(1)
+ }), () => {
let {xhr, promise} = this.context.fetchPushLocaleDeviceCount(fields.audience_id, fields.target, this.state.locales);
promise.then((localeDeviceCountMap) => {
this.setState({ localeDeviceCountMap })
@@ -667,9 +675,9 @@ class PushNew extends DashboardView {
});
});
// calculate initial recipient count
- this.setState({
- recipientCount: Math.floor(this.state.deviceCount * 0.5)
- });
+ this.setState((prev) => ({
+ recipientCount: Math.floor(prev.deviceCount * 0.5)
+ }));
}
// disable translation if experiment is enabled
if (fields.translation_enable && value) {
diff --git a/src/dashboard/Settings/SettingsData.react.js b/src/dashboard/Settings/SettingsData.react.js
index 4b2a37e931..5d693d929e 100644
--- a/src/dashboard/Settings/SettingsData.react.js
+++ b/src/dashboard/Settings/SettingsData.react.js
@@ -36,8 +36,9 @@ export default class SettingsData extends React.Component {
saveChanges(changes) {
let promise = this.context.saveSettingsFields(changes)
promise.then(({successes}) => {
- let newFields = {...this.state.fields, ...successes};
- this.setState({fields: newFields});
+ this.setState((prev) => ({
+ fields: {...prev.fields, ...successes}
+ }));
});
return promise;
}