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 }; + }); }} /> { - let filters = this.state.filters; - filters[index] = { - col: filter.col, - op: filter.op, - json_path: filter.json_path, - json_scalar_op: filter.json_scalar_op, - val: e.target.value - }; - 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: filter.json_scalar_op, + val: e.target.value + }; + return { filters }; + }); }} /> ); @@ -428,38 +440,42 @@ export default class ExplorerQueryComposer extends React.Component { value={Constraints[filter.op].name} options={availableFilters[filter.col].map((c) => Constraints[c].name)} onChange={(val) => { - let filters = this.state.filters; - filters[index] = { - col: filter.col, - op: constraintLookup[val], - val: filter.val - }; - this.setState({ filters }); + this.setState((prev) => { + let filters = prev.filters; + filters[index] = { + col: filter.col, + op: constraintLookup[val], + val: filter.val + }; + return { filters }; + }); }} /> { - let filters = this.state.filters; - let newFilter = null; - if (isJSONView) { - newFilter = { - col: filter.col, - op: filter.op, - val: filter.val, - json_path: e.target.value, - json_scalar_op: filter.json_scalar_op - }; - } else { - newFilter = { - col: filter.col, - op: filter.op, - val: e.target.value + this.setState((prev) => { + let filters = prev.filters; + let newFilter = null; + if (isJSONView) { + newFilter = { + col: filter.col, + op: filter.op, + val: filter.val, + json_path: e.target.value, + json_scalar_op: filter.json_scalar_op + }; + } else { + newFilter = { + col: filter.col, + op: filter.op, + val: e.target.value + } } - } - filters[index] = newFilter; - this.setState({ filters }); + filters[index] = newFilter; + return { filters }; + }); }} ref={setFocus} /> @@ -476,23 +492,27 @@ export default class ExplorerQueryComposer extends React.Component { value={Constraints[filter.op].name} options={availableFilters[filter.col].map((c) => Constraints[c].name)} onChange={(val) => { - let filters = this.state.filters; - filters[index] = { - col: filter.col, - op: constraintLookup[val], - val: null - }; - this.setState({ filters }); + this.setState((prev) => { + let filters = prev.filters; + filters[index] = { + col: filter.col, + op: constraintLookup[val], + val: null + }; + return { filters }; + }); }} /> {fieldView(type, filter.val, (val) => { - let filters = this.state.filters; - filters[index] = { - col: filter.col, - op: filter.op, - val: val - }; - this.setState({ filters }); + this.setState((prev) => { + let filters = prev.filters; + filters[index] = { + col: filter.col, + op: filter.op, + val: val + }; + return { filters }; + }); })} ); @@ -508,13 +528,15 @@ export default class ExplorerQueryComposer extends React.Component { value={filter.col} options={FIELD_LABELS[this.state.source]} onChange={(val) => { - let filters = this.state.filters; - filters[index] = { - col: val, - op: '$eq', - val: null - }; - this.setState({ filters }); + this.setState((prev) => { + let filters = prev.filters; + filters[index] = { + col: val, + op: '$eq', + val: null + }; + return { filters }; + }); }} /> @@ -542,12 +564,14 @@ export default class ExplorerQueryComposer extends React.Component { value={order.col} options={this.getOrderOptions()} onChange={(val) => { - let orders = this.state.orders; - orders[index] = { - col: val, - asc: ORDER_LABELS[0] - }; - this.setState({ orders }); + this.setState((prev) => { + let orders = prev.orders; + orders[index] = { + col: val, + asc: ORDER_LABELS[0] + }; + return { orders }; + }); }} color='blue' width='100%' /> @@ -558,9 +582,11 @@ export default class ExplorerQueryComposer extends React.Component { value={order.asc} options={ORDER_LABELS} onChange={(val) => { - let orders = this.state.orders; - orders[index].asc = val; - this.setState({ orders }); + this.setState((prev) => { + let orders = prev.orders; + orders[index].asc = val; + return { orders }; + }); }} color='blue' width='100%' /> diff --git a/src/components/FlowView/FlowView.react.js b/src/components/FlowView/FlowView.react.js index 275f272b4e..6f5c9b41ec 100644 --- a/src/components/FlowView/FlowView.react.js +++ b/src/components/FlowView/FlowView.react.js @@ -23,13 +23,16 @@ export default class FlowView extends React.Component { } componentWillReceiveProps(props) { - let newChanges = {...this.state.changes}; - for (let k in props.initialFields) { - if (this.state.changes[k] === props.initialFields[k]) { - delete newChanges[k]; + this.setState((prev) => { + let newChanges = {...prev.changes}; + for (let k in props.initialFields) { + if (prev.changes[k] === props.initialFields[k]) { + delete newChanges[k]; + } } - } - this.setState({changes: newChanges}); + + return {changes: newChanges}; + }); } currentFields() { @@ -53,11 +56,11 @@ export default class FlowView extends React.Component { //Modify stored state in case component recieves new props, //as componentWillReceiveProps would otherwise clobber this change. this.state.changes[key] = value; - this.setState({ - saveState: preserveSavingState ? this.state.saveState : SaveButton.States.WAITING, + this.setState((prev) => ({ + saveState: preserveSavingState ? prev.saveState : SaveButton.States.WAITING, saveError: '', changes: newChanges, - }); + })); } } diff --git a/src/components/GeoPointEditor/GeoPointEditor.react.js b/src/components/GeoPointEditor/GeoPointEditor.react.js index 597bc529ee..12ad4f09f5 100644 --- a/src/components/GeoPointEditor/GeoPointEditor.react.js +++ b/src/components/GeoPointEditor/GeoPointEditor.react.js @@ -130,7 +130,7 @@ export default class GeoPointEditor extends React.Component { } } - this.setState({ [target]: validateNumeric(value) ? value : this.state[target] }); + this.setState((prev) => ({ [target]: validateNumeric(value) ? value : prev[target] })); }; return (
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; }