From 83b21e90d29ad381af1fdce44244d832ce9eb091 Mon Sep 17 00:00:00 2001
From: Yamagishi Kazutoshi <ykzts@desire.sh>
Date: Wed, 4 May 2022 15:52:19 +0000
Subject: [PATCH] Bump React from 16.14.0 to 18.1.0

---
 .../__tests__/autosuggest_emoji-test.js       |   1 -
 .../components/__tests__/avatar-test.js       |   1 -
 .../__tests__/avatar_overlay-test.js          |   1 -
 .../components/__tests__/button-test.js       |   1 -
 .../components/__tests__/display_name-test.js |   1 -
 app/javascript/mastodon/components/account.js |   9 +-
 .../mastodon/components/admin/Counter.js      |  16 +-
 .../mastodon/components/admin/Dimension.js    |   4 +-
 .../components/admin/ReportReasonSelector.js  |   8 +-
 .../mastodon/components/admin/Retention.js    |   4 +-
 .../mastodon/components/admin/Trends.js       |   4 +-
 .../mastodon/components/animated_number.js    |   6 +-
 .../mastodon/components/attachment_list.js    |   1 -
 .../mastodon/components/autosuggest_emoji.js  |   4 +-
 .../components/autosuggest_hashtag.js         |   4 +-
 .../mastodon/components/autosuggest_input.js  |   3 +-
 .../components/autosuggest_textarea.js        |   3 +-
 app/javascript/mastodon/components/avatar.js  |   4 +-
 .../mastodon/components/avatar_composite.js   |   4 +-
 .../mastodon/components/avatar_overlay.js     |   4 +-
 .../mastodon/components/blurhash.js           |   4 +-
 app/javascript/mastodon/components/button.js  |   4 +-
 app/javascript/mastodon/components/check.js   |   2 -
 app/javascript/mastodon/components/column.js  |   4 +-
 .../mastodon/components/column_back_button.js |   4 +-
 .../components/column_back_button_slim.js     |   1 -
 .../mastodon/components/column_header.js      |   4 +-
 .../mastodon/components/common_counter.js     |   1 -
 .../mastodon/components/display_name.js       |   4 +-
 app/javascript/mastodon/components/domain.js  |   1 -
 .../mastodon/components/dropdown_menu.js      |  12 +-
 .../components/edited_timestamp/index.js      |   4 +-
 .../mastodon/components/error_boundary.js     |   4 +-
 app/javascript/mastodon/components/gifv.js    |   6 +-
 app/javascript/mastodon/components/hashtag.js |   6 +-
 app/javascript/mastodon/components/icon.js    |   4 +-
 .../mastodon/components/icon_button.js        |  10 +-
 .../mastodon/components/icon_with_badge.js    |   1 -
 .../mastodon/components/inline_account.js     |   4 +-
 .../intersection_observer_article.js          |   8 +-
 .../mastodon/components/load_gap.js           |   4 +-
 .../mastodon/components/load_more.js          |   4 +-
 .../mastodon/components/load_pending.js       |   4 +-
 .../mastodon/components/loading_indicator.js  |   1 -
 app/javascript/mastodon/components/logo.js    |   2 -
 .../mastodon/components/media_attachments.js  |   1 -
 .../mastodon/components/media_gallery.js      |   8 +-
 .../mastodon/components/missing_indicator.js  |   1 -
 .../mastodon/components/modal_root.js         |   6 +-
 .../mastodon/components/permalink.js          |   4 +-
 .../picture_in_picture_placeholder.js         |   4 +-
 app/javascript/mastodon/components/poll.js    |   1 -
 .../mastodon/components/radio_button.js       |   4 +-
 .../components/regeneration_indicator.js      |   1 -
 .../mastodon/components/relative_timestamp.js |   8 +-
 .../mastodon/components/scrollable_list.js    |  12 +-
 .../mastodon/components/setting_text.js       |   4 +-
 .../mastodon/components/short_number.js       |   4 +-
 .../mastodon/components/skeleton.js           |   1 -
 app/javascript/mastodon/components/status.js  |   1 -
 .../mastodon/components/status_action_bar.js  |   1 -
 .../mastodon/components/status_content.js     |   4 +-
 .../mastodon/components/status_list.js        |   1 -
 .../mastodon/components/timeline_hint.js      |   1 -
 .../mastodon/containers/account_container.js  |   1 -
 .../mastodon/containers/admin_component.js    |   4 +-
 .../mastodon/containers/compose_container.js  |   4 +-
 .../mastodon/containers/domain_container.js   |   1 -
 .../mastodon/containers/mastodon.js           |   4 +-
 .../mastodon/containers/media_container.js    |  10 +-
 .../mastodon/containers/status_container.js   |   1 -
 .../mastodon/containers/timeline_container.js |  12 +-
 .../account/components/account_note.js        |  10 +-
 .../features/account/components/header.js     |   5 +-
 .../account_gallery/components/media_item.js  |   1 -
 .../features/account_gallery/index.js         |   1 -
 .../account_timeline/components/header.js     |   1 -
 .../components/limited_account_hint.js        |   4 +-
 .../account_timeline/components/moved_note.js |   1 -
 .../containers/header_container.js            |   1 -
 .../features/account_timeline/index.js        |   1 -
 .../mastodon/features/audio/index.js          |   4 +-
 .../mastodon/features/blocks/index.js         |   3 +-
 .../features/bookmarked_statuses/index.js     |   3 +-
 .../components/column_settings.js             |   4 +-
 .../features/community_timeline/index.js      |   4 +-
 .../features/compose/components/action_bar.js |   4 +-
 .../compose/components/autosuggest_account.js |   1 -
 .../compose/components/character_counter.js   |   4 +-
 .../compose/components/compose_form.js        |   1 -
 .../components/emoji_picker_dropdown.js       |  12 +-
 .../compose/components/language_dropdown.js   |   6 +-
 .../compose/components/navigation_bar.js      |   1 -
 .../compose/components/poll_button.js         |   4 +-
 .../features/compose/components/poll_form.js  |   4 +-
 .../compose/components/privacy_dropdown.js    |   8 +-
 .../compose/components/reply_indicator.js     |   1 -
 .../features/compose/components/search.js     |   6 +-
 .../compose/components/search_results.js      |   1 -
 .../compose/components/text_icon_button.js    |   4 +-
 .../features/compose/components/upload.js     |   1 -
 .../compose/components/upload_button.js       |   1 -
 .../compose/components/upload_form.js         |   1 -
 .../compose/components/upload_progress.js     |   4 +-
 .../features/compose/components/warning.js    |   4 +-
 .../containers/sensitive_button_container.js  |   4 +-
 .../compose/containers/warning_container.js   |   1 -
 .../mastodon/features/compose/index.js        |   4 +-
 .../components/conversation.js                |   1 -
 .../components/conversations_list.js          |   1 -
 .../features/direct_timeline/index.js         |   4 +-
 .../directory/components/account_card.js      |   1 -
 .../mastodon/features/directory/index.js      |   4 +-
 .../mastodon/features/domain_blocks/index.js  |   3 +-
 .../features/explore/components/story.js      |   8 +-
 .../mastodon/features/explore/index.js        |   8 +-
 .../mastodon/features/explore/links.js        |   4 +-
 .../mastodon/features/explore/results.js      |   8 +-
 .../mastodon/features/explore/statuses.js     |   4 +-
 .../mastodon/features/explore/suggestions.js  |   4 +-
 .../mastodon/features/explore/tags.js         |   4 +-
 .../features/favourited_statuses/index.js     |   3 +-
 .../mastodon/features/favourites/index.js     |   5 +-
 .../components/account.js                     |   1 -
 .../features/follow_recommendations/index.js  |   5 +-
 .../components/account_authorize.js           |   1 -
 .../features/follow_requests/index.js         |   3 +-
 .../mastodon/features/followers/index.js      |   1 -
 .../mastodon/features/following/index.js      |   1 -
 .../features/generic_not_found/index.js       |   1 -
 .../components/announcements.js               |   4 +-
 .../getting_started/components/trends.js      |   1 -
 .../features/getting_started/index.js         |   1 -
 .../components/column_settings.js             |   4 +-
 .../features/hashtag_timeline/index.js        |   6 +-
 .../components/column_settings.js             |   4 +-
 .../mastodon/features/home_timeline/index.js  |   4 +-
 .../features/keyboard_shortcuts/index.js      |   1 -
 .../features/list_adder/components/account.js |   1 -
 .../features/list_adder/components/list.js    |   1 -
 .../mastodon/features/list_adder/index.js     |   1 -
 .../list_editor/components/account.js         |   1 -
 .../list_editor/components/edit_list_form.js  |   4 +-
 .../features/list_editor/components/search.js |   4 +-
 .../mastodon/features/list_editor/index.js    |   1 -
 .../mastodon/features/list_timeline/index.js  |   6 +-
 .../lists/components/new_list_form.js         |   4 +-
 .../mastodon/features/lists/index.js          |   3 +-
 .../mastodon/features/mutes/index.js          |   3 +-
 .../components/clear_column_button.js         |   4 +-
 .../components/column_settings.js             |   4 +-
 .../notifications/components/filter_bar.js    |   4 +-
 .../components/follow_request.js              |   5 +-
 .../components/grant_permission_button.js     |   4 +-
 .../notifications/components/notification.js  |   1 -
 .../notifications_permission_banner.js        |   4 +-
 .../notifications/components/report.js        |   5 +-
 .../components/setting_toggle.js              |   4 +-
 .../mastodon/features/notifications/index.js  |   6 +-
 .../picture_in_picture/components/footer.js   |   1 -
 .../picture_in_picture/components/header.js   |   1 -
 .../features/picture_in_picture/index.js      |   4 +-
 .../features/pinned_statuses/index.js         |   3 +-
 .../components/column_settings.js             |   4 +-
 .../features/public_timeline/index.js         |   4 +-
 .../mastodon/features/reblogs/index.js        |   5 +-
 .../mastodon/features/report/category.js      |   8 +-
 .../mastodon/features/report/comment.js       |  12 +-
 .../features/report/components/option.js      |   4 +-
 .../report/components/status_check_box.js     |   4 +-
 .../mastodon/features/report/rules.js         |   8 +-
 .../mastodon/features/report/statuses.js      |   8 +-
 .../mastodon/features/report/thanks.js        |  12 +-
 .../features/standalone/compose/index.js      |   4 +-
 .../standalone/hashtag_timeline/index.js      |   4 +-
 .../standalone/public_timeline/index.js       |   4 +-
 .../features/status/components/action_bar.js  |   4 +-
 .../features/status/components/card.js        |   6 +-
 .../status/components/detailed_status.js      |  23 ++-
 .../mastodon/features/status/index.js         |   5 +-
 .../ui/components/__tests__/column-test.js    |   1 -
 .../features/ui/components/actions_modal.js   |   1 -
 .../features/ui/components/audio_modal.js     |   1 -
 .../features/ui/components/block_modal.js     |   4 +-
 .../features/ui/components/boost_modal.js     |   1 -
 .../mastodon/features/ui/components/bundle.js |   8 +-
 .../ui/components/bundle_column_error.js      |   4 +-
 .../ui/components/bundle_modal_error.js       |   4 +-
 .../mastodon/features/ui/components/column.js |   4 +-
 .../features/ui/components/column_header.js   |   4 +-
 .../features/ui/components/column_link.js     |   1 -
 .../features/ui/components/column_loading.js  |   1 -
 .../ui/components/column_subheading.js        |   1 -
 .../features/ui/components/columns_area.js    |  10 +-
 .../ui/components/compare_history_modal.js    |   8 +-
 .../features/ui/components/compose_panel.js   |   4 +-
 .../ui/components/confirmation_modal.js       |   4 +-
 .../features/ui/components/drawer_loading.js  |   2 -
 .../features/ui/components/embed_modal.js     |   1 -
 .../ui/components/focal_point_modal.js        |   8 +-
 .../ui/components/follow_requests_nav_link.js |   4 +-
 .../features/ui/components/image_loader.js    |   6 +-
 .../features/ui/components/link_footer.js     |   4 +-
 .../features/ui/components/list_panel.js      |   1 -
 .../features/ui/components/media_modal.js     |   1 -
 .../features/ui/components/modal_loading.js   |   2 -
 .../features/ui/components/modal_root.js      |   4 +-
 .../features/ui/components/mute_modal.js      |   4 +-
 .../ui/components/navigation_panel.js         |   1 -
 .../features/ui/components/report_modal.js    |   1 -
 .../features/ui/components/tabs_bar.js        |   6 +-
 .../features/ui/components/upload_area.js     |   4 +-
 .../features/ui/components/video_modal.js     |   1 -
 .../features/ui/components/zoomable_image.js  |   8 +-
 app/javascript/mastodon/features/ui/index.js  |   8 +-
 .../features/ui/util/react_router_helpers.js  |   8 +-
 .../features/ui/util/reduced_motion.js        |   4 +-
 .../mastodon/features/video/index.js          |   6 +-
 app/javascript/mastodon/main.js               |  18 +-
 app/javascript/packs/about.js                 |  19 +-
 app/javascript/packs/admin.js                 |  25 +--
 app/javascript/packs/public.js                |  30 ++--
 app/javascript/packs/share.js                 |  18 +-
 babel.config.js                               |   1 +
 package.json                                  |  10 +-
 yarn.lock                                     | 167 +++++++++---------
 226 files changed, 531 insertions(+), 610 deletions(-)

diff --git a/app/javascript/mastodon/components/__tests__/autosuggest_emoji-test.js b/app/javascript/mastodon/components/__tests__/autosuggest_emoji-test.js
index 05616e44482..80aa33a187a 100644
--- a/app/javascript/mastodon/components/__tests__/autosuggest_emoji-test.js
+++ b/app/javascript/mastodon/components/__tests__/autosuggest_emoji-test.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import renderer from 'react-test-renderer';
 import AutosuggestEmoji from '../autosuggest_emoji';
 
diff --git a/app/javascript/mastodon/components/__tests__/avatar-test.js b/app/javascript/mastodon/components/__tests__/avatar-test.js
index dd3f7b7d210..d4f81e273d5 100644
--- a/app/javascript/mastodon/components/__tests__/avatar-test.js
+++ b/app/javascript/mastodon/components/__tests__/avatar-test.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import renderer from 'react-test-renderer';
 import { fromJS } from 'immutable';
 import Avatar from '../avatar';
diff --git a/app/javascript/mastodon/components/__tests__/avatar_overlay-test.js b/app/javascript/mastodon/components/__tests__/avatar_overlay-test.js
index 44addea832f..a5b418c6c98 100644
--- a/app/javascript/mastodon/components/__tests__/avatar_overlay-test.js
+++ b/app/javascript/mastodon/components/__tests__/avatar_overlay-test.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import renderer from 'react-test-renderer';
 import { fromJS } from 'immutable';
 import AvatarOverlay from '../avatar_overlay';
diff --git a/app/javascript/mastodon/components/__tests__/button-test.js b/app/javascript/mastodon/components/__tests__/button-test.js
index f5a649f70e3..82d307e8430 100644
--- a/app/javascript/mastodon/components/__tests__/button-test.js
+++ b/app/javascript/mastodon/components/__tests__/button-test.js
@@ -1,5 +1,4 @@
 import { render, fireEvent, screen } from '@testing-library/react';
-import React from 'react';
 import renderer from 'react-test-renderer';
 import Button from '../button';
 
diff --git a/app/javascript/mastodon/components/__tests__/display_name-test.js b/app/javascript/mastodon/components/__tests__/display_name-test.js
index 0d040c4cd8c..2506cc78002 100644
--- a/app/javascript/mastodon/components/__tests__/display_name-test.js
+++ b/app/javascript/mastodon/components/__tests__/display_name-test.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import renderer from 'react-test-renderer';
 import { fromJS }  from 'immutable';
 import DisplayName from '../display_name';
diff --git a/app/javascript/mastodon/components/account.js b/app/javascript/mastodon/components/account.js
index af9f119c82c..98709742c48 100644
--- a/app/javascript/mastodon/components/account.js
+++ b/app/javascript/mastodon/components/account.js
@@ -1,4 +1,3 @@
-import React, { Fragment } from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
 import Avatar from './avatar';
@@ -72,10 +71,10 @@ class Account extends ImmutablePureComponent {
 
     if (hidden) {
       return (
-        <Fragment>
+        <>
           {account.get('display_name')}
           {account.get('username')}
-        </Fragment>
+        </>
       );
     }
 
@@ -103,10 +102,10 @@ class Account extends ImmutablePureComponent {
           hidingNotificationsButton = <IconButton active icon='bell-slash' title={intl.formatMessage(messages.mute_notifications, { name: account.get('username')  })} onClick={this.handleMuteNotifications} />;
         }
         buttons = (
-          <Fragment>
+          <>
             <IconButton active icon='volume-up' title={intl.formatMessage(messages.unmute, { name: account.get('username') })} onClick={this.handleMute} />
             {hidingNotificationsButton}
-          </Fragment>
+          </>
         );
       } else if (defaultAction === 'mute') {
         buttons = <IconButton icon='volume-off' title={intl.formatMessage(messages.mute, { name: account.get('username') })} onClick={this.handleMute} />;
diff --git a/app/javascript/mastodon/components/admin/Counter.js b/app/javascript/mastodon/components/admin/Counter.js
index 5a5b2b869e0..9eaafbca889 100644
--- a/app/javascript/mastodon/components/admin/Counter.js
+++ b/app/javascript/mastodon/components/admin/Counter.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import api from 'mastodon/api';
 import { FormattedNumber } from 'react-intl';
@@ -24,7 +24,7 @@ const percIncrease = (a, b) => {
   return percent;
 };
 
-export default class Counter extends React.PureComponent {
+export default class Counter extends PureComponent {
 
   static propTypes = {
     measure: PropTypes.string.isRequired,
@@ -62,25 +62,25 @@ export default class Counter extends React.PureComponent {
 
     if (loading) {
       content = (
-        <React.Fragment>
+        <>
           <span className='sparkline__value__total'><Skeleton width={43} /></span>
           <span className='sparkline__value__change'><Skeleton width={43} /></span>
-        </React.Fragment>
+        </>
       );
     } else {
       const measure = data[0];
       const percentChange = measure.previous_total && percIncrease(measure.previous_total * 1, measure.total * 1);
 
       content = (
-        <React.Fragment>
+        <>
           <span className='sparkline__value__total'>{measure.human_value || <FormattedNumber value={measure.total} />}</span>
           {measure.previous_total && (<span className={classNames('sparkline__value__change', { positive: percentChange > 0, negative: percentChange < 0 })}>{percentChange > 0 && '+'}<FormattedNumber value={percentChange} style='percent' /></span>)}
-        </React.Fragment>
+        </>
       );
     }
 
     const inner = (
-      <React.Fragment>
+      <>
         <div className='sparkline__value'>
           {content}
         </div>
@@ -96,7 +96,7 @@ export default class Counter extends React.PureComponent {
             </Sparklines>
           )}
         </div>
-      </React.Fragment>
+      </>
     );
 
     if (href) {
diff --git a/app/javascript/mastodon/components/admin/Dimension.js b/app/javascript/mastodon/components/admin/Dimension.js
index 977c8208df1..090cea9fcb8 100644
--- a/app/javascript/mastodon/components/admin/Dimension.js
+++ b/app/javascript/mastodon/components/admin/Dimension.js
@@ -1,11 +1,11 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import api from 'mastodon/api';
 import { FormattedNumber } from 'react-intl';
 import { roundTo10 } from 'mastodon/utils/numbers';
 import Skeleton from 'mastodon/components/skeleton';
 
-export default class Dimension extends React.PureComponent {
+export default class Dimension extends PureComponent {
 
   static propTypes = {
     dimension: PropTypes.string.isRequired,
diff --git a/app/javascript/mastodon/components/admin/ReportReasonSelector.js b/app/javascript/mastodon/components/admin/ReportReasonSelector.js
index 1f91d25175a..3cdff8997fd 100644
--- a/app/javascript/mastodon/components/admin/ReportReasonSelector.js
+++ b/app/javascript/mastodon/components/admin/ReportReasonSelector.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import api from 'mastodon/api';
 import { injectIntl, defineMessages } from 'react-intl';
@@ -10,7 +10,7 @@ const messages = defineMessages({
   violation: { id: 'report.categories.violation', defaultMessage: 'Content violates one or more server rules' },
 });
 
-class Category extends React.PureComponent {
+class Category extends PureComponent {
 
   static propTypes = {
     id: PropTypes.string.isRequired,
@@ -52,7 +52,7 @@ class Category extends React.PureComponent {
 
 }
 
-class Rule extends React.PureComponent {
+class Rule extends PureComponent {
 
   static propTypes = {
     id: PropTypes.string.isRequired,
@@ -85,7 +85,7 @@ class Rule extends React.PureComponent {
 }
 
 export default @injectIntl
-class ReportReasonSelector extends React.PureComponent {
+class ReportReasonSelector extends PureComponent {
 
   static propTypes = {
     id: PropTypes.string.isRequired,
diff --git a/app/javascript/mastodon/components/admin/Retention.js b/app/javascript/mastodon/components/admin/Retention.js
index 47c9e715136..c724bd5ce1c 100644
--- a/app/javascript/mastodon/components/admin/Retention.js
+++ b/app/javascript/mastodon/components/admin/Retention.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import api from 'mastodon/api';
 import { FormattedMessage, FormattedNumber, FormattedDate } from 'react-intl';
@@ -14,7 +14,7 @@ const dateForCohort = cohort => {
   }
 };
 
-export default class Retention extends React.PureComponent {
+export default class Retention extends PureComponent {
 
   static propTypes = {
     start_at: PropTypes.string,
diff --git a/app/javascript/mastodon/components/admin/Trends.js b/app/javascript/mastodon/components/admin/Trends.js
index 635bdf37d56..bb7777a542b 100644
--- a/app/javascript/mastodon/components/admin/Trends.js
+++ b/app/javascript/mastodon/components/admin/Trends.js
@@ -1,11 +1,11 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import api from 'mastodon/api';
 import { FormattedMessage } from 'react-intl';
 import classNames from 'classnames';
 import Hashtag from 'mastodon/components/hashtag';
 
-export default class Trends extends React.PureComponent {
+export default class Trends extends PureComponent {
 
   static propTypes = {
     limit: PropTypes.number.isRequired,
diff --git a/app/javascript/mastodon/components/animated_number.js b/app/javascript/mastodon/components/animated_number.js
index fbe948c5b02..46bb82dafcc 100644
--- a/app/javascript/mastodon/components/animated_number.js
+++ b/app/javascript/mastodon/components/animated_number.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import { FormattedNumber } from 'react-intl';
 import TransitionMotion from 'react-motion/lib/TransitionMotion';
@@ -15,7 +15,7 @@ const obfuscatedCount = count => {
   }
 };
 
-export default class AnimatedNumber extends React.PureComponent {
+export default class AnimatedNumber extends PureComponent {
 
   static propTypes = {
     value: PropTypes.number.isRequired,
@@ -26,7 +26,7 @@ export default class AnimatedNumber extends React.PureComponent {
     direction: 1,
   };
 
-  componentWillReceiveProps (nextProps) {
+  UNSAFE_componentWillReceiveProps (nextProps) {
     if (nextProps.value > this.props.value) {
       this.setState({ direction: 1 });
     } else if (nextProps.value < this.props.value) {
diff --git a/app/javascript/mastodon/components/attachment_list.js b/app/javascript/mastodon/components/attachment_list.js
index 0e23889dedc..e65c7956b58 100644
--- a/app/javascript/mastodon/components/attachment_list.js
+++ b/app/javascript/mastodon/components/attachment_list.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
 import ImmutablePureComponent from 'react-immutable-pure-component';
diff --git a/app/javascript/mastodon/components/autosuggest_emoji.js b/app/javascript/mastodon/components/autosuggest_emoji.js
index 4937e4d9845..8afbdd9cb5c 100644
--- a/app/javascript/mastodon/components/autosuggest_emoji.js
+++ b/app/javascript/mastodon/components/autosuggest_emoji.js
@@ -1,9 +1,9 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import unicodeMapping from '../features/emoji/emoji_unicode_mapping_light';
 import { assetHost } from 'mastodon/utils/config';
 
-export default class AutosuggestEmoji extends React.PureComponent {
+export default class AutosuggestEmoji extends PureComponent {
 
   static propTypes = {
     emoji: PropTypes.object.isRequired,
diff --git a/app/javascript/mastodon/components/autosuggest_hashtag.js b/app/javascript/mastodon/components/autosuggest_hashtag.js
index 9e9d888f83b..4fd23ec9a8b 100644
--- a/app/javascript/mastodon/components/autosuggest_hashtag.js
+++ b/app/javascript/mastodon/components/autosuggest_hashtag.js
@@ -1,9 +1,9 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import ShortNumber from 'mastodon/components/short_number';
 import { FormattedMessage } from 'react-intl';
 
-export default class AutosuggestHashtag extends React.PureComponent {
+export default class AutosuggestHashtag extends PureComponent {
 
   static propTypes = {
     tag: PropTypes.shape({
diff --git a/app/javascript/mastodon/components/autosuggest_input.js b/app/javascript/mastodon/components/autosuggest_input.js
index 12d44b5d0b2..5c6ac019c60 100644
--- a/app/javascript/mastodon/components/autosuggest_input.js
+++ b/app/javascript/mastodon/components/autosuggest_input.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import AutosuggestAccountContainer from '../features/compose/containers/autosuggest_account_container';
 import AutosuggestEmoji from './autosuggest_emoji';
 import AutosuggestHashtag from './autosuggest_hashtag';
@@ -152,7 +151,7 @@ export default class AutosuggestInput extends ImmutablePureComponent {
     this.input.focus();
   }
 
-  componentWillReceiveProps (nextProps) {
+  UNSAFE_componentWillReceiveProps (nextProps) {
     if (nextProps.suggestions !== this.props.suggestions && nextProps.suggestions.size > 0 && this.state.suggestionsHidden && this.state.focused) {
       this.setState({ suggestionsHidden: false });
     }
diff --git a/app/javascript/mastodon/components/autosuggest_textarea.js b/app/javascript/mastodon/components/autosuggest_textarea.js
index 08b9cd80bbf..7d17107be00 100644
--- a/app/javascript/mastodon/components/autosuggest_textarea.js
+++ b/app/javascript/mastodon/components/autosuggest_textarea.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import AutosuggestAccountContainer from '../features/compose/containers/autosuggest_account_container';
 import AutosuggestEmoji from './autosuggest_emoji';
 import AutosuggestHashtag from './autosuggest_hashtag';
@@ -152,7 +151,7 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
     this.textarea.focus();
   }
 
-  componentWillReceiveProps (nextProps) {
+  UNSAFE_componentWillReceiveProps (nextProps) {
     if (nextProps.suggestions !== this.props.suggestions && nextProps.suggestions.size > 0 && this.state.suggestionsHidden && this.state.focused) {
       this.setState({ suggestionsHidden: false });
     }
diff --git a/app/javascript/mastodon/components/avatar.js b/app/javascript/mastodon/components/avatar.js
index 12ab7d2dfe4..3394a8e2655 100644
--- a/app/javascript/mastodon/components/avatar.js
+++ b/app/javascript/mastodon/components/avatar.js
@@ -1,10 +1,10 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import { autoPlayGif } from '../initial_state';
 import classNames from 'classnames';
 
-export default class Avatar extends React.PureComponent {
+export default class Avatar extends PureComponent {
 
   static propTypes = {
     account: ImmutablePropTypes.map,
diff --git a/app/javascript/mastodon/components/avatar_composite.js b/app/javascript/mastodon/components/avatar_composite.js
index 5d5b897492f..2a49bf4264b 100644
--- a/app/javascript/mastodon/components/avatar_composite.js
+++ b/app/javascript/mastodon/components/avatar_composite.js
@@ -1,9 +1,9 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import { autoPlayGif } from '../initial_state';
 
-export default class AvatarComposite extends React.PureComponent {
+export default class AvatarComposite extends PureComponent {
 
   static propTypes = {
     accounts: ImmutablePropTypes.list.isRequired,
diff --git a/app/javascript/mastodon/components/avatar_overlay.js b/app/javascript/mastodon/components/avatar_overlay.js
index 3ec1d77304f..0de08ef0361 100644
--- a/app/javascript/mastodon/components/avatar_overlay.js
+++ b/app/javascript/mastodon/components/avatar_overlay.js
@@ -1,9 +1,9 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import { autoPlayGif } from '../initial_state';
 
-export default class AvatarOverlay extends React.PureComponent {
+export default class AvatarOverlay extends PureComponent {
 
   static propTypes = {
     account: ImmutablePropTypes.map.isRequired,
diff --git a/app/javascript/mastodon/components/blurhash.js b/app/javascript/mastodon/components/blurhash.js
index 2af5cfc5685..21fbebc70ab 100644
--- a/app/javascript/mastodon/components/blurhash.js
+++ b/app/javascript/mastodon/components/blurhash.js
@@ -1,7 +1,7 @@
 // @ts-check
 
 import { decode } from 'blurhash';
-import React, { useRef, useEffect } from 'react';
+import { memo, useRef, useEffect } from 'react';
 import PropTypes from 'prop-types';
 
 /**
@@ -62,4 +62,4 @@ Blurhash.propTypes = {
   dummy: PropTypes.bool,
 };
 
-export default React.memo(Blurhash);
+export default memo(Blurhash);
diff --git a/app/javascript/mastodon/components/button.js b/app/javascript/mastodon/components/button.js
index 85b2d78ca9e..f153d8c9ccd 100644
--- a/app/javascript/mastodon/components/button.js
+++ b/app/javascript/mastodon/components/button.js
@@ -1,8 +1,8 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import classNames from 'classnames';
 
-export default class Button extends React.PureComponent {
+export default class Button extends PureComponent {
 
   static propTypes = {
     text: PropTypes.node,
diff --git a/app/javascript/mastodon/components/check.js b/app/javascript/mastodon/components/check.js
index ee2ef1595a2..d818480b7ba 100644
--- a/app/javascript/mastodon/components/check.js
+++ b/app/javascript/mastodon/components/check.js
@@ -1,5 +1,3 @@
-import React from 'react';
-
 const Check = () => (
   <svg width='14' height='11' viewBox='0 0 14 11'>
     <path d='M11.264 0L5.26 6.004 2.103 2.847 0 4.95l5.26 5.26 8.108-8.107L11.264 0' fill='currentColor' fillRule='evenodd' />
diff --git a/app/javascript/mastodon/components/column.js b/app/javascript/mastodon/components/column.js
index 239824a4fec..94ffa998e38 100644
--- a/app/javascript/mastodon/components/column.js
+++ b/app/javascript/mastodon/components/column.js
@@ -1,9 +1,9 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import { supportsPassiveEvents } from 'detect-passive-events';
 import { scrollTop } from '../scroll';
 
-export default class Column extends React.PureComponent {
+export default class Column extends PureComponent {
 
   static propTypes = {
     children: PropTypes.node,
diff --git a/app/javascript/mastodon/components/column_back_button.js b/app/javascript/mastodon/components/column_back_button.js
index d97622705e5..754afb1bdf9 100644
--- a/app/javascript/mastodon/components/column_back_button.js
+++ b/app/javascript/mastodon/components/column_back_button.js
@@ -1,10 +1,10 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import { FormattedMessage } from 'react-intl';
 import PropTypes from 'prop-types';
 import Icon from 'mastodon/components/icon';
 import { createPortal } from 'react-dom';
 
-export default class ColumnBackButton extends React.PureComponent {
+export default class ColumnBackButton extends PureComponent {
 
   static contextTypes = {
     router: PropTypes.object,
diff --git a/app/javascript/mastodon/components/column_back_button_slim.js b/app/javascript/mastodon/components/column_back_button_slim.js
index cc8bfb1515b..64476351786 100644
--- a/app/javascript/mastodon/components/column_back_button_slim.js
+++ b/app/javascript/mastodon/components/column_back_button_slim.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import { FormattedMessage } from 'react-intl';
 import ColumnBackButton from './column_back_button';
 import Icon from 'mastodon/components/icon';
diff --git a/app/javascript/mastodon/components/column_header.js b/app/javascript/mastodon/components/column_header.js
index cbbc490a83b..51d806e4ee1 100644
--- a/app/javascript/mastodon/components/column_header.js
+++ b/app/javascript/mastodon/components/column_header.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import { createPortal } from 'react-dom';
 import classNames from 'classnames';
@@ -13,7 +13,7 @@ const messages = defineMessages({
 });
 
 export default @injectIntl
-class ColumnHeader extends React.PureComponent {
+class ColumnHeader extends PureComponent {
 
   static contextTypes = {
     router: PropTypes.object,
diff --git a/app/javascript/mastodon/components/common_counter.js b/app/javascript/mastodon/components/common_counter.js
index dd9b62de9b1..5d169c9332e 100644
--- a/app/javascript/mastodon/components/common_counter.js
+++ b/app/javascript/mastodon/components/common_counter.js
@@ -1,5 +1,4 @@
 // @ts-check
-import React from 'react';
 import { FormattedMessage } from 'react-intl';
 
 /**
diff --git a/app/javascript/mastodon/components/display_name.js b/app/javascript/mastodon/components/display_name.js
index 7ccfbd0cd5f..df6136e9483 100644
--- a/app/javascript/mastodon/components/display_name.js
+++ b/app/javascript/mastodon/components/display_name.js
@@ -1,9 +1,9 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
 import { autoPlayGif } from 'mastodon/initial_state';
 
-export default class DisplayName extends React.PureComponent {
+export default class DisplayName extends PureComponent {
 
   static propTypes = {
     account: ImmutablePropTypes.map.isRequired,
diff --git a/app/javascript/mastodon/components/domain.js b/app/javascript/mastodon/components/domain.js
index 697065d874d..935d260f486 100644
--- a/app/javascript/mastodon/components/domain.js
+++ b/app/javascript/mastodon/components/domain.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import PropTypes from 'prop-types';
 import IconButton from './icon_button';
 import { defineMessages, injectIntl } from 'react-intl';
diff --git a/app/javascript/mastodon/components/dropdown_menu.js b/app/javascript/mastodon/components/dropdown_menu.js
index 4b4ad83555f..f29d4eb539d 100644
--- a/app/javascript/mastodon/components/dropdown_menu.js
+++ b/app/javascript/mastodon/components/dropdown_menu.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { Children, PureComponent, cloneElement } from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import IconButton from './icon_button';
@@ -12,7 +12,7 @@ import { CircularProgress } from 'mastodon/components/loading_indicator';
 const listenerOptions = supportsPassiveEvents ? { passive: true } : false;
 let id = 0;
 
-class DropdownMenu extends React.PureComponent {
+class DropdownMenu extends PureComponent {
 
   static contextTypes = {
     router: PropTypes.object,
@@ -178,7 +178,7 @@ class DropdownMenu extends React.PureComponent {
 
 }
 
-export default class Dropdown extends React.PureComponent {
+export default class Dropdown extends PureComponent {
 
   static contextTypes = {
     router: PropTypes.object,
@@ -313,7 +313,7 @@ export default class Dropdown extends React.PureComponent {
 
     const open = this.state.id === openDropdownId;
 
-    const button = children ? React.cloneElement(React.Children.only(children), {
+    const button = children ? cloneElement(Children.only(children), {
       ref: this.setTargetRef,
       onClick: this.handleClick,
       onMouseDown: this.handleMouseDown,
@@ -335,7 +335,7 @@ export default class Dropdown extends React.PureComponent {
     );
 
     return (
-      <React.Fragment>
+      <>
         {button}
 
         <Overlay show={open} placement={dropdownPlacement} target={this.findTarget}>
@@ -350,7 +350,7 @@ export default class Dropdown extends React.PureComponent {
             onItemClick={this.handleItemClick}
           />
         </Overlay>
-      </React.Fragment>
+      </>
     );
   }
 
diff --git a/app/javascript/mastodon/components/edited_timestamp/index.js b/app/javascript/mastodon/components/edited_timestamp/index.js
index bebf938865b..679ec4e4cd5 100644
--- a/app/javascript/mastodon/components/edited_timestamp/index.js
+++ b/app/javascript/mastodon/components/edited_timestamp/index.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import { FormattedMessage, injectIntl } from 'react-intl';
 import Icon from 'mastodon/components/icon';
@@ -18,7 +18,7 @@ const mapDispatchToProps = (dispatch, { statusId }) => ({
 
 export default @connect(null, mapDispatchToProps)
 @injectIntl
-class EditedTimestamp extends React.PureComponent {
+class EditedTimestamp extends PureComponent {
 
   static propTypes = {
     statusId: PropTypes.string.isRequired,
diff --git a/app/javascript/mastodon/components/error_boundary.js b/app/javascript/mastodon/components/error_boundary.js
index ca4a2cfe14b..7ca9facd2aa 100644
--- a/app/javascript/mastodon/components/error_boundary.js
+++ b/app/javascript/mastodon/components/error_boundary.js
@@ -1,10 +1,10 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import { FormattedMessage } from 'react-intl';
 import { version, source_url } from 'mastodon/initial_state';
 import StackTrace from 'stacktrace-js';
 
-export default class ErrorBoundary extends React.PureComponent {
+export default class ErrorBoundary extends PureComponent {
 
   static propTypes = {
     children: PropTypes.node,
diff --git a/app/javascript/mastodon/components/gifv.js b/app/javascript/mastodon/components/gifv.js
index b775e52005b..848411a1195 100644
--- a/app/javascript/mastodon/components/gifv.js
+++ b/app/javascript/mastodon/components/gifv.js
@@ -1,7 +1,7 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 
-export default class GIFV extends React.PureComponent {
+export default class GIFV extends PureComponent {
 
   static propTypes = {
     src: PropTypes.string.isRequired,
@@ -19,7 +19,7 @@ export default class GIFV extends React.PureComponent {
     this.setState({ loading: false });
   }
 
-  componentWillReceiveProps (nextProps) {
+  UNSAFE_componentWillReceiveProps (nextProps) {
     if (nextProps.src !== this.props.src) {
       this.setState({ loading: true });
     }
diff --git a/app/javascript/mastodon/components/hashtag.js b/app/javascript/mastodon/components/hashtag.js
index 7f442d189ca..5fee2bfc877 100644
--- a/app/javascript/mastodon/components/hashtag.js
+++ b/app/javascript/mastodon/components/hashtag.js
@@ -1,5 +1,5 @@
 // @ts-check
-import React from 'react';
+import { Component } from 'react';
 import { Sparklines, SparklinesCurve } from 'react-sparklines';
 import { FormattedMessage } from 'react-intl';
 import PropTypes from 'prop-types';
@@ -9,7 +9,7 @@ import ShortNumber from 'mastodon/components/short_number';
 import Skeleton from 'mastodon/components/skeleton';
 import classNames from 'classnames';
 
-class SilentErrorBoundary extends React.Component {
+class SilentErrorBoundary extends Component {
 
   static propTypes = {
     children: PropTypes.node,
@@ -68,7 +68,7 @@ const Hashtag = ({ name, href, to, people, uses, history, className }) => (
   <div className={classNames('trends__item', className)}>
     <div className='trends__item__name'>
       <Permalink href={href} to={to}>
-        {name ? <React.Fragment>#<span>{name}</span></React.Fragment> : <Skeleton width={50} />}
+        {name ? <>#<span>{name}</span></> : <Skeleton width={50} />}
       </Permalink>
 
       {typeof people !== 'undefined' ? <ShortNumber value={people} renderer={accountsCountRenderer} /> : <Skeleton width={100} />}
diff --git a/app/javascript/mastodon/components/icon.js b/app/javascript/mastodon/components/icon.js
index d8a17722fed..11178dd1275 100644
--- a/app/javascript/mastodon/components/icon.js
+++ b/app/javascript/mastodon/components/icon.js
@@ -1,8 +1,8 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import classNames from 'classnames';
 
-export default class Icon extends React.PureComponent {
+export default class Icon extends PureComponent {
 
   static propTypes = {
     id: PropTypes.string.isRequired,
diff --git a/app/javascript/mastodon/components/icon_button.js b/app/javascript/mastodon/components/icon_button.js
index 81743a1dbe1..1c1c3244b06 100644
--- a/app/javascript/mastodon/components/icon_button.js
+++ b/app/javascript/mastodon/components/icon_button.js
@@ -1,10 +1,10 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import classNames from 'classnames';
 import Icon from 'mastodon/components/icon';
 import AnimatedNumber from 'mastodon/components/animated_number';
 
-export default class IconButton extends React.PureComponent {
+export default class IconButton extends PureComponent {
 
   static propTypes = {
     className: PropTypes.string,
@@ -44,7 +44,7 @@ export default class IconButton extends React.PureComponent {
     deactivate: false,
   }
 
-  componentWillReceiveProps (nextProps) {
+  UNSAFE_componentWillReceiveProps (nextProps) {
     if (!nextProps.animate) return;
 
     if (this.props.active && !nextProps.active) {
@@ -126,9 +126,9 @@ export default class IconButton extends React.PureComponent {
     }
 
     let contents = (
-      <React.Fragment>
+      <>
         <Icon id={icon} fixedWidth aria-hidden='true' /> {typeof counter !== 'undefined' && <span className='icon-button__counter'><AnimatedNumber value={counter} obfuscate={obfuscateCount} /></span>}
-      </React.Fragment>
+      </>
     );
 
     if (href) {
diff --git a/app/javascript/mastodon/components/icon_with_badge.js b/app/javascript/mastodon/components/icon_with_badge.js
index 4214eccfde9..812ebfe5732 100644
--- a/app/javascript/mastodon/components/icon_with_badge.js
+++ b/app/javascript/mastodon/components/icon_with_badge.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import PropTypes from 'prop-types';
 import Icon from 'mastodon/components/icon';
 
diff --git a/app/javascript/mastodon/components/inline_account.js b/app/javascript/mastodon/components/inline_account.js
index a1b4955904b..c5c30fb9894 100644
--- a/app/javascript/mastodon/components/inline_account.js
+++ b/app/javascript/mastodon/components/inline_account.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import { connect } from 'react-redux';
 import { makeGetAccount } from 'mastodon/selectors';
@@ -15,7 +15,7 @@ const makeMapStateToProps = () => {
 };
 
 export default @connect(makeMapStateToProps)
-class InlineAccount extends React.PureComponent {
+class InlineAccount extends PureComponent {
 
   static propTypes = {
     account: ImmutablePropTypes.map.isRequired,
diff --git a/app/javascript/mastodon/components/intersection_observer_article.js b/app/javascript/mastodon/components/intersection_observer_article.js
index 26f85fa4004..88a12b2425f 100644
--- a/app/javascript/mastodon/components/intersection_observer_article.js
+++ b/app/javascript/mastodon/components/intersection_observer_article.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { cloneElement, Component } from 'react';
 import PropTypes from 'prop-types';
 import scheduleIdleTask from '../features/ui/util/schedule_idle_task';
 import getRectFromEntry from '../features/ui/util/get_rect_from_entry';
@@ -6,7 +6,7 @@ import getRectFromEntry from '../features/ui/util/get_rect_from_entry';
 // Diff these props in the "unrendered" state
 const updateOnPropsForUnrendered = ['id', 'index', 'listLength', 'cachedHeight'];
 
-export default class IntersectionObserverArticle extends React.Component {
+export default class IntersectionObserverArticle extends Component {
 
   static propTypes = {
     intersectionObserverWrapper: PropTypes.object.isRequired,
@@ -115,14 +115,14 @@ export default class IntersectionObserverArticle extends React.Component {
           data-id={id}
           tabIndex='0'
         >
-          {children && React.cloneElement(children, { hidden: true })}
+          {children && cloneElement(children, { hidden: true })}
         </article>
       );
     }
 
     return (
       <article ref={this.handleRef} aria-posinset={index + 1} aria-setsize={listLength} data-id={id} tabIndex='0'>
-        {children && React.cloneElement(children, { hidden: false })}
+        {children && cloneElement(children, { hidden: false })}
       </article>
     );
   }
diff --git a/app/javascript/mastodon/components/load_gap.js b/app/javascript/mastodon/components/load_gap.js
index a44d55d0935..ca2077a239a 100644
--- a/app/javascript/mastodon/components/load_gap.js
+++ b/app/javascript/mastodon/components/load_gap.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import { injectIntl, defineMessages } from 'react-intl';
 import Icon from 'mastodon/components/icon';
@@ -8,7 +8,7 @@ const messages = defineMessages({
 });
 
 export default @injectIntl
-class LoadGap extends React.PureComponent {
+class LoadGap extends PureComponent {
 
   static propTypes = {
     disabled: PropTypes.bool,
diff --git a/app/javascript/mastodon/components/load_more.js b/app/javascript/mastodon/components/load_more.js
index 389c3e1e115..f7bd70d7da4 100644
--- a/app/javascript/mastodon/components/load_more.js
+++ b/app/javascript/mastodon/components/load_more.js
@@ -1,8 +1,8 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import { FormattedMessage } from 'react-intl';
 import PropTypes from 'prop-types';
 
-export default class LoadMore extends React.PureComponent {
+export default class LoadMore extends PureComponent {
 
   static propTypes = {
     onClick: PropTypes.func,
diff --git a/app/javascript/mastodon/components/load_pending.js b/app/javascript/mastodon/components/load_pending.js
index 7e27024036a..96727c7f93c 100644
--- a/app/javascript/mastodon/components/load_pending.js
+++ b/app/javascript/mastodon/components/load_pending.js
@@ -1,8 +1,8 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import { FormattedMessage } from 'react-intl';
 import PropTypes from 'prop-types';
 
-export default class LoadPending extends React.PureComponent {
+export default class LoadPending extends PureComponent {
 
   static propTypes = {
     onClick: PropTypes.func,
diff --git a/app/javascript/mastodon/components/loading_indicator.js b/app/javascript/mastodon/components/loading_indicator.js
index 33c59d94c02..c3f7a4e9ef0 100644
--- a/app/javascript/mastodon/components/loading_indicator.js
+++ b/app/javascript/mastodon/components/loading_indicator.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import PropTypes from 'prop-types';
 
 export const CircularProgress = ({ size, strokeWidth }) => {
diff --git a/app/javascript/mastodon/components/logo.js b/app/javascript/mastodon/components/logo.js
index d1c7f08a91d..26df5753d8a 100644
--- a/app/javascript/mastodon/components/logo.js
+++ b/app/javascript/mastodon/components/logo.js
@@ -1,5 +1,3 @@
-import React from 'react';
-
 const Logo = () => (
   <svg viewBox='0 0 216.4144 232.00976' className='logo'>
     <use xlinkHref='#mastodon-svg-logo' />
diff --git a/app/javascript/mastodon/components/media_attachments.js b/app/javascript/mastodon/components/media_attachments.js
index d27720de41c..7ebe743d634 100644
--- a/app/javascript/mastodon/components/media_attachments.js
+++ b/app/javascript/mastodon/components/media_attachments.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import ImmutablePureComponent from 'react-immutable-pure-component';
diff --git a/app/javascript/mastodon/components/media_gallery.js b/app/javascript/mastodon/components/media_gallery.js
index 2e7ce2e608f..25d34cb58df 100644
--- a/app/javascript/mastodon/components/media_gallery.js
+++ b/app/javascript/mastodon/components/media_gallery.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
 import { is } from 'immutable';
@@ -14,7 +14,7 @@ const messages = defineMessages({
   toggle_visible: { id: 'media_gallery.toggle_visible', defaultMessage: '{number, plural, one {Hide image} other {Hide images}}' },
 });
 
-class Item extends React.PureComponent {
+class Item extends PureComponent {
 
   static propTypes = {
     attachment: ImmutablePropTypes.map.isRequired,
@@ -221,7 +221,7 @@ class Item extends React.PureComponent {
 }
 
 export default @injectIntl
-class MediaGallery extends React.PureComponent {
+class MediaGallery extends PureComponent {
 
   static propTypes = {
     sensitive: PropTypes.bool,
@@ -255,7 +255,7 @@ class MediaGallery extends React.PureComponent {
     window.removeEventListener('resize', this.handleResize);
   }
 
-  componentWillReceiveProps (nextProps) {
+  UNSAFE_componentWillReceiveProps (nextProps) {
     if (!is(nextProps.media, this.props.media) && nextProps.visible === undefined) {
       this.setState({ visible: displayMedia !== 'hide_all' && !nextProps.sensitive || displayMedia === 'show_all' });
     } else if (!is(nextProps.visible, this.props.visible) && nextProps.visible !== undefined) {
diff --git a/app/javascript/mastodon/components/missing_indicator.js b/app/javascript/mastodon/components/missing_indicator.js
index 7b0101bab85..eeb88f6bcd2 100644
--- a/app/javascript/mastodon/components/missing_indicator.js
+++ b/app/javascript/mastodon/components/missing_indicator.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import PropTypes from 'prop-types';
 import { FormattedMessage } from 'react-intl';
 import illustration from 'mastodon/../images/elephant_ui_disappointed.svg';
diff --git a/app/javascript/mastodon/components/modal_root.js b/app/javascript/mastodon/components/modal_root.js
index b894aeaf989..7a23e00055d 100644
--- a/app/javascript/mastodon/components/modal_root.js
+++ b/app/javascript/mastodon/components/modal_root.js
@@ -1,10 +1,10 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import 'wicg-inert';
 import { createBrowserHistory } from 'history';
 import { multiply } from 'color-blend';
 
-export default class ModalRoot extends React.PureComponent {
+export default class ModalRoot extends PureComponent {
 
   static contextTypes = {
     router: PropTypes.object,
@@ -57,7 +57,7 @@ export default class ModalRoot extends React.PureComponent {
     this.history = this.context.router ? this.context.router.history : createBrowserHistory();
   }
 
-  componentWillReceiveProps (nextProps) {
+  UNSAFE_componentWillReceiveProps (nextProps) {
     if (!!nextProps.children && !this.props.children) {
       this.activeElement = document.activeElement;
 
diff --git a/app/javascript/mastodon/components/permalink.js b/app/javascript/mastodon/components/permalink.js
index b369e98126d..285bf0831f7 100644
--- a/app/javascript/mastodon/components/permalink.js
+++ b/app/javascript/mastodon/components/permalink.js
@@ -1,7 +1,7 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 
-export default class Permalink extends React.PureComponent {
+export default class Permalink extends PureComponent {
 
   static contextTypes = {
     router: PropTypes.object,
diff --git a/app/javascript/mastodon/components/picture_in_picture_placeholder.js b/app/javascript/mastodon/components/picture_in_picture_placeholder.js
index 19d15c18b16..ddb818951f8 100644
--- a/app/javascript/mastodon/components/picture_in_picture_placeholder.js
+++ b/app/javascript/mastodon/components/picture_in_picture_placeholder.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import Icon from 'mastodon/components/icon';
 import { removePictureInPicture } from 'mastodon/actions/picture_in_picture';
@@ -7,7 +7,7 @@ import { debounce } from 'lodash';
 import { FormattedMessage } from 'react-intl';
 
 export default @connect()
-class PictureInPicturePlaceholder extends React.PureComponent {
+class PictureInPicturePlaceholder extends PureComponent {
 
   static propTypes = {
     width: PropTypes.number,
diff --git a/app/javascript/mastodon/components/poll.js b/app/javascript/mastodon/components/poll.js
index 85aa28816ca..cb0fe71313e 100644
--- a/app/javascript/mastodon/components/poll.js
+++ b/app/javascript/mastodon/components/poll.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import ImmutablePureComponent from 'react-immutable-pure-component';
diff --git a/app/javascript/mastodon/components/radio_button.js b/app/javascript/mastodon/components/radio_button.js
index 0496fa2868a..00894e171c6 100644
--- a/app/javascript/mastodon/components/radio_button.js
+++ b/app/javascript/mastodon/components/radio_button.js
@@ -1,8 +1,8 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import classNames from 'classnames';
 
-export default class RadioButton extends React.PureComponent {
+export default class RadioButton extends PureComponent {
 
   static propTypes = {
     value: PropTypes.string.isRequired,
diff --git a/app/javascript/mastodon/components/regeneration_indicator.js b/app/javascript/mastodon/components/regeneration_indicator.js
index 52696a4a724..dbefc7a9b94 100644
--- a/app/javascript/mastodon/components/regeneration_indicator.js
+++ b/app/javascript/mastodon/components/regeneration_indicator.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import { FormattedMessage } from 'react-intl';
 import illustration from 'mastodon/../images/elephant_ui_working.svg';
 
diff --git a/app/javascript/mastodon/components/relative_timestamp.js b/app/javascript/mastodon/components/relative_timestamp.js
index 51248033927..5b5a998bb51 100644
--- a/app/javascript/mastodon/components/relative_timestamp.js
+++ b/app/javascript/mastodon/components/relative_timestamp.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { Component } from 'react';
 import { injectIntl, defineMessages } from 'react-intl';
 import PropTypes from 'prop-types';
 
@@ -122,7 +122,7 @@ const timeRemainingString = (intl, date, now, timeGiven = true) => {
 };
 
 export default @injectIntl
-class RelativeTimestamp extends React.Component {
+class RelativeTimestamp extends Component {
 
   static propTypes = {
     intl: PropTypes.object.isRequired,
@@ -149,7 +149,7 @@ class RelativeTimestamp extends React.Component {
       this.state.now !== nextState.now;
   }
 
-  componentWillReceiveProps (nextProps) {
+  UNSAFE_componentWillReceiveProps (nextProps) {
     if (this.props.timestamp !== nextProps.timestamp) {
       this.setState({ now: this.props.intl.now() });
     }
@@ -159,7 +159,7 @@ class RelativeTimestamp extends React.Component {
     this._scheduleNextUpdate(this.props, this.state);
   }
 
-  componentWillUpdate (nextProps, nextState) {
+  UNSAFE_componentWillUpdate (nextProps, nextState) {
     this._scheduleNextUpdate(nextProps, nextState);
   }
 
diff --git a/app/javascript/mastodon/components/scrollable_list.js b/app/javascript/mastodon/components/scrollable_list.js
index 91d04bf4d8e..0d1ee7036c4 100644
--- a/app/javascript/mastodon/components/scrollable_list.js
+++ b/app/javascript/mastodon/components/scrollable_list.js
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import { Children, PureComponent, cloneElement } from 'react';
 import ScrollContainer from 'mastodon/containers/scroll_container';
 import PropTypes from 'prop-types';
 import IntersectionObserverArticleContainer from '../containers/intersection_observer_article_container';
@@ -182,8 +182,8 @@ class ScrollableList extends PureComponent {
   }
 
   getSnapshotBeforeUpdate (prevProps) {
-    const someItemInserted = React.Children.count(prevProps.children) > 0 &&
-      React.Children.count(prevProps.children) < React.Children.count(this.props.children) &&
+    const someItemInserted = Children.count(prevProps.children) > 0 &&
+      Children.count(prevProps.children) < Children.count(this.props.children) &&
       this.getFirstChildKey(prevProps) !== this.getFirstChildKey(this.props);
     const pendingChanged = (prevProps.numPending > 0) !== (this.props.numPending > 0);
 
@@ -291,7 +291,7 @@ class ScrollableList extends PureComponent {
   render () {
     const { children, scrollKey, trackScroll, showLoading, isLoading, hasMore, numPending, prepend, alwaysPrepend, append, emptyMessage, onLoadMore } = this.props;
     const { fullscreen } = this.state;
-    const childrenCount = React.Children.count(children);
+    const childrenCount = Children.count(children);
 
     const loadMore     = (hasMore && onLoadMore) ? <LoadMore visible={!isLoading} onClick={this.handleLoadMore} /> : null;
     const loadPending  = (numPending > 0) ? <LoadPending count={numPending} onClick={this.handleLoadPending} /> : null;
@@ -317,7 +317,7 @@ class ScrollableList extends PureComponent {
 
             {loadPending}
 
-            {React.Children.map(this.props.children, (child, index) => (
+            {Children.map(this.props.children, (child, index) => (
               <IntersectionObserverArticleContainer
                 key={child.key}
                 id={child.key}
@@ -326,7 +326,7 @@ class ScrollableList extends PureComponent {
                 intersectionObserverWrapper={this.intersectionObserverWrapper}
                 saveHeightKey={trackScroll ? `${this.context.router.route.location.key}:${scrollKey}` : null}
               >
-                {React.cloneElement(child, {
+                {cloneElement(child, {
                   getScrollPosition: this.getScrollPosition,
                   updateScrollBottom: this.updateScrollBottom,
                   cachedMediaWidth: this.state.cachedMediaWidth,
diff --git a/app/javascript/mastodon/components/setting_text.js b/app/javascript/mastodon/components/setting_text.js
index a6dde4c0f10..e0f3d42c36d 100644
--- a/app/javascript/mastodon/components/setting_text.js
+++ b/app/javascript/mastodon/components/setting_text.js
@@ -1,8 +1,8 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 
-export default class SettingText extends React.PureComponent {
+export default class SettingText extends PureComponent {
 
   static propTypes = {
     settings: ImmutablePropTypes.map.isRequired,
diff --git a/app/javascript/mastodon/components/short_number.js b/app/javascript/mastodon/components/short_number.js
index 535c17727d5..b9fecda6891 100644
--- a/app/javascript/mastodon/components/short_number.js
+++ b/app/javascript/mastodon/components/short_number.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { memo } from 'react';
 import PropTypes from 'prop-types';
 import { toShortNumber, pluralReady, DECIMAL_UNITS } from '../utils/numbers';
 import { FormattedMessage, FormattedNumber } from 'react-intl';
@@ -114,4 +114,4 @@ ShortNumberCounter.propTypes = {
   value: PropTypes.arrayOf(PropTypes.number),
 };
 
-export default React.memo(ShortNumber);
+export default memo(ShortNumber);
diff --git a/app/javascript/mastodon/components/skeleton.js b/app/javascript/mastodon/components/skeleton.js
index 09093e99c75..72174f6bbe7 100644
--- a/app/javascript/mastodon/components/skeleton.js
+++ b/app/javascript/mastodon/components/skeleton.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import PropTypes from 'prop-types';
 
 const Skeleton = ({ width, height }) => <span className='skeleton' style={{ width, height }}>&zwnj;</span>;
diff --git a/app/javascript/mastodon/components/status.js b/app/javascript/mastodon/components/status.js
index 4ca39282426..23ea0da186d 100644
--- a/app/javascript/mastodon/components/status.js
+++ b/app/javascript/mastodon/components/status.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
 import Avatar from './avatar';
diff --git a/app/javascript/mastodon/components/status_action_bar.js b/app/javascript/mastodon/components/status_action_bar.js
index ab8755be04c..8d6783e7416 100644
--- a/app/javascript/mastodon/components/status_action_bar.js
+++ b/app/javascript/mastodon/components/status_action_bar.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import { connect } from 'react-redux';
 import PropTypes from 'prop-types';
diff --git a/app/javascript/mastodon/components/status_content.js b/app/javascript/mastodon/components/status_content.js
index 724165ada07..675a895f35c 100644
--- a/app/javascript/mastodon/components/status_content.js
+++ b/app/javascript/mastodon/components/status_content.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
 import { FormattedMessage } from 'react-intl';
@@ -10,7 +10,7 @@ import { autoPlayGif } from 'mastodon/initial_state';
 
 const MAX_HEIGHT = 642; // 20px * 32 (+ 2px padding at the top)
 
-export default class StatusContent extends React.PureComponent {
+export default class StatusContent extends PureComponent {
 
   static contextTypes = {
     router: PropTypes.object,
diff --git a/app/javascript/mastodon/components/status_list.js b/app/javascript/mastodon/components/status_list.js
index 35e5749a33b..938aac89828 100644
--- a/app/javascript/mastodon/components/status_list.js
+++ b/app/javascript/mastodon/components/status_list.js
@@ -1,5 +1,4 @@
 import { debounce } from 'lodash';
-import React from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
 import StatusContainer from '../containers/status_container';
diff --git a/app/javascript/mastodon/components/timeline_hint.js b/app/javascript/mastodon/components/timeline_hint.js
index fb55a62ccae..fac08be0544 100644
--- a/app/javascript/mastodon/components/timeline_hint.js
+++ b/app/javascript/mastodon/components/timeline_hint.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import PropTypes from 'prop-types';
 import { FormattedMessage } from 'react-intl';
 
diff --git a/app/javascript/mastodon/containers/account_container.js b/app/javascript/mastodon/containers/account_container.js
index 5a5136dd186..f3d3e039c7c 100644
--- a/app/javascript/mastodon/containers/account_container.js
+++ b/app/javascript/mastodon/containers/account_container.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import { connect } from 'react-redux';
 import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 import { makeGetAccount } from '../selectors';
diff --git a/app/javascript/mastodon/containers/admin_component.js b/app/javascript/mastodon/containers/admin_component.js
index 816b44bd179..188485d40b4 100644
--- a/app/javascript/mastodon/containers/admin_component.js
+++ b/app/javascript/mastodon/containers/admin_component.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import { IntlProvider, addLocaleData } from 'react-intl';
 import { getLocale } from '../locales';
@@ -6,7 +6,7 @@ import { getLocale } from '../locales';
 const { localeData, messages } = getLocale();
 addLocaleData(localeData);
 
-export default class AdminComponent extends React.PureComponent {
+export default class AdminComponent extends PureComponent {
 
   static propTypes = {
     locale: PropTypes.string.isRequired,
diff --git a/app/javascript/mastodon/containers/compose_container.js b/app/javascript/mastodon/containers/compose_container.js
index 7bc7bbaa4dc..b0bc1d73787 100644
--- a/app/javascript/mastodon/containers/compose_container.js
+++ b/app/javascript/mastodon/containers/compose_container.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import { Provider } from 'react-redux';
 import PropTypes from 'prop-types';
 import configureStore from '../store/configureStore';
@@ -20,7 +20,7 @@ if (initialState) {
 
 store.dispatch(fetchCustomEmojis());
 
-export default class TimelineContainer extends React.PureComponent {
+export default class TimelineContainer extends PureComponent {
 
   static propTypes = {
     locale: PropTypes.string.isRequired,
diff --git a/app/javascript/mastodon/containers/domain_container.js b/app/javascript/mastodon/containers/domain_container.js
index 8a8ba1df12e..806bb81d10f 100644
--- a/app/javascript/mastodon/containers/domain_container.js
+++ b/app/javascript/mastodon/containers/domain_container.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import { connect } from 'react-redux';
 import { blockDomain, unblockDomain } from '../actions/domain_blocks';
 import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
diff --git a/app/javascript/mastodon/containers/mastodon.js b/app/javascript/mastodon/containers/mastodon.js
index 0c3f6afa855..dd0ab74174d 100644
--- a/app/javascript/mastodon/containers/mastodon.js
+++ b/app/javascript/mastodon/containers/mastodon.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import { Provider } from 'react-redux';
 import PropTypes from 'prop-types';
 import configureStore from '../store/configureStore';
@@ -28,7 +28,7 @@ const createIdentityContext = state => ({
   accessToken: state.meta.access_token,
 });
 
-export default class Mastodon extends React.PureComponent {
+export default class Mastodon extends PureComponent {
 
   static propTypes = {
     locale: PropTypes.string.isRequired,
diff --git a/app/javascript/mastodon/containers/media_container.js b/app/javascript/mastodon/containers/media_container.js
index 6ee1f0bd885..393886c5878 100644
--- a/app/javascript/mastodon/containers/media_container.js
+++ b/app/javascript/mastodon/containers/media_container.js
@@ -1,5 +1,5 @@
-import React, { PureComponent, Fragment } from 'react';
-import ReactDOM from 'react-dom';
+import { PureComponent } from 'react';
+import { createPortal } from 'react-dom';
 import PropTypes from 'prop-types';
 import { IntlProvider, addLocaleData } from 'react-intl';
 import { fromJS } from 'immutable';
@@ -74,7 +74,7 @@ export default class MediaContainer extends PureComponent {
 
     return (
       <IntlProvider locale={locale} messages={messages}>
-        <Fragment>
+        <>
           {[].map.call(components, (component, i) => {
             const componentName = component.getAttribute('data-component');
             const Component = MEDIA_COMPONENTS[componentName];
@@ -94,7 +94,7 @@ export default class MediaContainer extends PureComponent {
               }),
             });
 
-            return ReactDOM.createPortal(
+            return createPortal(
               <Component {...props} key={`media-${i}`} />,
               component,
             );
@@ -113,7 +113,7 @@ export default class MediaContainer extends PureComponent {
               />
             )}
           </ModalRoot>
-        </Fragment>
+        </>
       </IntlProvider>
     );
   }
diff --git a/app/javascript/mastodon/containers/status_container.js b/app/javascript/mastodon/containers/status_container.js
index ef0aca13a6d..3a24c23ccff 100644
--- a/app/javascript/mastodon/containers/status_container.js
+++ b/app/javascript/mastodon/containers/status_container.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import { connect } from 'react-redux';
 import Status from '../components/status';
 import { makeGetStatus, makeGetPictureInPicture } from '../selectors';
diff --git a/app/javascript/mastodon/containers/timeline_container.js b/app/javascript/mastodon/containers/timeline_container.js
index ed8095f90e2..eefb5f0f22b 100644
--- a/app/javascript/mastodon/containers/timeline_container.js
+++ b/app/javascript/mastodon/containers/timeline_container.js
@@ -1,5 +1,5 @@
-import React, { Fragment } from 'react';
-import ReactDOM from 'react-dom';
+import { PureComponent } from 'react';
+import { createPortal } from 'react-dom';
 import { Provider } from 'react-redux';
 import PropTypes from 'prop-types';
 import configureStore from '../store/configureStore';
@@ -20,7 +20,7 @@ if (initialState) {
   store.dispatch(hydrateStore(initialState));
 }
 
-export default class TimelineContainer extends React.PureComponent {
+export default class TimelineContainer extends PureComponent {
 
   static propTypes = {
     locale: PropTypes.string.isRequired,
@@ -46,14 +46,14 @@ export default class TimelineContainer extends React.PureComponent {
     return (
       <IntlProvider locale={locale} messages={messages}>
         <Provider store={store}>
-          <Fragment>
+          <>
             {timeline}
 
-            {ReactDOM.createPortal(
+            {createPortal(
               <ModalContainer />,
               document.getElementById('modal-container'),
             )}
-          </Fragment>
+          </>
         </Provider>
       </IntlProvider>
     );
diff --git a/app/javascript/mastodon/features/account/components/account_note.js b/app/javascript/mastodon/features/account/components/account_note.js
index 1787ce1abc3..81dfd50face 100644
--- a/app/javascript/mastodon/features/account/components/account_note.js
+++ b/app/javascript/mastodon/features/account/components/account_note.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
 import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
@@ -10,7 +10,7 @@ const messages = defineMessages({
   placeholder: { id: 'account_note.placeholder', defaultMessage: 'Click to add a note' },
 });
 
-class InlineAlert extends React.PureComponent {
+class InlineAlert extends PureComponent {
 
   static propTypes = {
     show: PropTypes.bool,
@@ -22,7 +22,7 @@ class InlineAlert extends React.PureComponent {
 
   static TRANSITION_DELAY = 200;
 
-  componentWillReceiveProps (nextProps) {
+  UNSAFE_componentWillReceiveProps (nextProps) {
     if (!this.props.show && nextProps.show) {
       this.setState({ mountMessage: true });
     } else if (this.props.show && !nextProps.show) {
@@ -59,11 +59,11 @@ class AccountNote extends ImmutablePureComponent {
     saved: false,
   };
 
-  componentWillMount () {
+  UNSAFE_componentWillMount () {
     this._reset();
   }
 
-  componentWillReceiveProps (nextProps) {
+  UNSAFE_componentWillReceiveProps (nextProps) {
     const accountWillChange = !is(this.props.account, nextProps.account);
     const newState = {};
 
diff --git a/app/javascript/mastodon/features/account/components/header.js b/app/javascript/mastodon/features/account/components/header.js
index 8e6b9f0634e..baba3291118 100644
--- a/app/javascript/mastodon/features/account/components/header.js
+++ b/app/javascript/mastodon/features/account/components/header.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
 import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
@@ -282,10 +281,10 @@ class Header extends ImmutablePureComponent {
             {!suspended && (
               <div className='account__header__tabs__buttons'>
                 {!hidden && (
-                  <React.Fragment>
+                  <>
                     {actionBtn}
                     {bellBtn}
-                  </React.Fragment>
+                  </>
                 )}
 
                 <DropdownMenuContainer items={menu} icon='ellipsis-v' size={24} direction='right' />
diff --git a/app/javascript/mastodon/features/account_gallery/components/media_item.js b/app/javascript/mastodon/features/account_gallery/components/media_item.js
index ba7ec46a330..f4cc91970a2 100644
--- a/app/javascript/mastodon/features/account_gallery/components/media_item.js
+++ b/app/javascript/mastodon/features/account_gallery/components/media_item.js
@@ -4,7 +4,6 @@ import Icon from 'mastodon/components/icon';
 import { autoPlayGif, displayMedia, useBlurhash } from 'mastodon/initial_state';
 import { isIOS } from 'mastodon/is_mobile';
 import PropTypes from 'prop-types';
-import React from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 
diff --git a/app/javascript/mastodon/features/account_gallery/index.js b/app/javascript/mastodon/features/account_gallery/index.js
index cc0bfa9baa3..2d319652177 100644
--- a/app/javascript/mastodon/features/account_gallery/index.js
+++ b/app/javascript/mastodon/features/account_gallery/index.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import { connect } from 'react-redux';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
diff --git a/app/javascript/mastodon/features/account_timeline/components/header.js b/app/javascript/mastodon/features/account_timeline/components/header.js
index fab0bc597fb..31312e4eeea 100644
--- a/app/javascript/mastodon/features/account_timeline/components/header.js
+++ b/app/javascript/mastodon/features/account_timeline/components/header.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
 import InnerHeader from '../../account/components/header';
diff --git a/app/javascript/mastodon/features/account_timeline/components/limited_account_hint.js b/app/javascript/mastodon/features/account_timeline/components/limited_account_hint.js
index 6b025596ca5..192333dc356 100644
--- a/app/javascript/mastodon/features/account_timeline/components/limited_account_hint.js
+++ b/app/javascript/mastodon/features/account_timeline/components/limited_account_hint.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import { connect } from 'react-redux';
 import { revealAccount } from 'mastodon/actions/accounts';
@@ -14,7 +14,7 @@ const mapDispatchToProps = (dispatch, { accountId }) => ({
 });
 
 export default @connect(() => {}, mapDispatchToProps)
-class LimitedAccountHint extends React.PureComponent {
+class LimitedAccountHint extends PureComponent {
 
   static propTypes = {
     accountId: PropTypes.string.isRequired,
diff --git a/app/javascript/mastodon/features/account_timeline/components/moved_note.js b/app/javascript/mastodon/features/account_timeline/components/moved_note.js
index 2e32d660f84..48afc9e41d4 100644
--- a/app/javascript/mastodon/features/account_timeline/components/moved_note.js
+++ b/app/javascript/mastodon/features/account_timeline/components/moved_note.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import { FormattedMessage } from 'react-intl';
diff --git a/app/javascript/mastodon/features/account_timeline/containers/header_container.js b/app/javascript/mastodon/features/account_timeline/containers/header_container.js
index 371794dd758..07dc502ecd9 100644
--- a/app/javascript/mastodon/features/account_timeline/containers/header_container.js
+++ b/app/javascript/mastodon/features/account_timeline/containers/header_container.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import { connect } from 'react-redux';
 import { makeGetAccount, getAccountHidden } from '../../../selectors';
 import Header from '../components/header';
diff --git a/app/javascript/mastodon/features/account_timeline/index.js b/app/javascript/mastodon/features/account_timeline/index.js
index 5b592c5a76c..11599f24f54 100644
--- a/app/javascript/mastodon/features/account_timeline/index.js
+++ b/app/javascript/mastodon/features/account_timeline/index.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import { connect } from 'react-redux';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
diff --git a/app/javascript/mastodon/features/audio/index.js b/app/javascript/mastodon/features/audio/index.js
index c47f55dd1ea..b12de2ed3b2 100644
--- a/app/javascript/mastodon/features/audio/index.js
+++ b/app/javascript/mastodon/features/audio/index.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import { defineMessages, injectIntl } from 'react-intl';
 import { formatTime } from 'mastodon/features/video';
@@ -21,7 +21,7 @@ const TICK_SIZE = 10;
 const PADDING   = 180;
 
 export default @injectIntl
-class Audio extends React.PureComponent {
+class Audio extends PureComponent {
 
   static propTypes = {
     src: PropTypes.string.isRequired,
diff --git a/app/javascript/mastodon/features/blocks/index.js b/app/javascript/mastodon/features/blocks/index.js
index e00f2b60e0f..1e87a42c6bf 100644
--- a/app/javascript/mastodon/features/blocks/index.js
+++ b/app/javascript/mastodon/features/blocks/index.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import { connect } from 'react-redux';
 import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 import ImmutablePureComponent from 'react-immutable-pure-component';
@@ -36,7 +35,7 @@ class Blocks extends ImmutablePureComponent {
     multiColumn: PropTypes.bool,
   };
 
-  componentWillMount () {
+  UNSAFE_componentWillMount () {
     this.props.dispatch(fetchBlocks());
   }
 
diff --git a/app/javascript/mastodon/features/bookmarked_statuses/index.js b/app/javascript/mastodon/features/bookmarked_statuses/index.js
index 8f41b0f9514..8e7f9724c70 100644
--- a/app/javascript/mastodon/features/bookmarked_statuses/index.js
+++ b/app/javascript/mastodon/features/bookmarked_statuses/index.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import { connect } from 'react-redux';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
@@ -35,7 +34,7 @@ class Bookmarks extends ImmutablePureComponent {
     isLoading: PropTypes.bool,
   };
 
-  componentWillMount () {
+  UNSAFE_componentWillMount () {
     this.props.dispatch(fetchBookmarkedStatuses());
   }
 
diff --git a/app/javascript/mastodon/features/community_timeline/components/column_settings.js b/app/javascript/mastodon/features/community_timeline/components/column_settings.js
index 0cb6db8836b..03ce451e4dc 100644
--- a/app/javascript/mastodon/features/community_timeline/components/column_settings.js
+++ b/app/javascript/mastodon/features/community_timeline/components/column_settings.js
@@ -1,11 +1,11 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import { injectIntl, FormattedMessage } from 'react-intl';
 import SettingToggle from '../../notifications/components/setting_toggle';
 
 export default @injectIntl
-class ColumnSettings extends React.PureComponent {
+class ColumnSettings extends PureComponent {
 
   static propTypes = {
     settings: ImmutablePropTypes.map.isRequired,
diff --git a/app/javascript/mastodon/features/community_timeline/index.js b/app/javascript/mastodon/features/community_timeline/index.js
index 30f77604867..aaa622d6d01 100644
--- a/app/javascript/mastodon/features/community_timeline/index.js
+++ b/app/javascript/mastodon/features/community_timeline/index.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import { connect } from 'react-redux';
 import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 import PropTypes from 'prop-types';
@@ -29,7 +29,7 @@ const mapStateToProps = (state, { columnId }) => {
 
 export default @connect(mapStateToProps)
 @injectIntl
-class CommunityTimeline extends React.PureComponent {
+class CommunityTimeline extends PureComponent {
 
   static contextTypes = {
     router: PropTypes.object,
diff --git a/app/javascript/mastodon/features/compose/components/action_bar.js b/app/javascript/mastodon/features/compose/components/action_bar.js
index 4ff0b7b94b6..836296fe5f9 100644
--- a/app/javascript/mastodon/features/compose/components/action_bar.js
+++ b/app/javascript/mastodon/features/compose/components/action_bar.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
 import DropdownMenuContainer from '../../../containers/dropdown_menu_container';
@@ -20,7 +20,7 @@ const messages = defineMessages({
 });
 
 export default @injectIntl
-class ActionBar extends React.PureComponent {
+class ActionBar extends PureComponent {
 
   static propTypes = {
     account: ImmutablePropTypes.map.isRequired,
diff --git a/app/javascript/mastodon/features/compose/components/autosuggest_account.js b/app/javascript/mastodon/features/compose/components/autosuggest_account.js
index 1451be0e646..30afeb0e5ec 100644
--- a/app/javascript/mastodon/features/compose/components/autosuggest_account.js
+++ b/app/javascript/mastodon/features/compose/components/autosuggest_account.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import Avatar from '../../../components/avatar';
 import DisplayName from '../../../components/display_name';
 import ImmutablePropTypes from 'react-immutable-proptypes';
diff --git a/app/javascript/mastodon/features/compose/components/character_counter.js b/app/javascript/mastodon/features/compose/components/character_counter.js
index 0ecfc9141d8..15fc77bdcd2 100644
--- a/app/javascript/mastodon/features/compose/components/character_counter.js
+++ b/app/javascript/mastodon/features/compose/components/character_counter.js
@@ -1,8 +1,8 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import { length } from 'stringz';
 
-export default class CharacterCounter extends React.PureComponent {
+export default class CharacterCounter extends PureComponent {
 
   static propTypes = {
     text: PropTypes.string.isRequired,
diff --git a/app/javascript/mastodon/features/compose/components/compose_form.js b/app/javascript/mastodon/features/compose/components/compose_form.js
index cd10d0edabe..96ac744fbf2 100644
--- a/app/javascript/mastodon/features/compose/components/compose_form.js
+++ b/app/javascript/mastodon/features/compose/components/compose_form.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import CharacterCounter from './character_counter';
 import Button from '../../../components/button';
 import ImmutablePropTypes from 'react-immutable-proptypes';
diff --git a/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js b/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js
index f433e4de9fa..5aa5165c191 100644
--- a/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js
+++ b/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 import { EmojiPicker as EmojiPickerAsync } from '../../ui/util/async-components';
@@ -47,7 +47,7 @@ const notFoundFn = () => (
   </div>
 );
 
-class ModifierPickerMenu extends React.PureComponent {
+class ModifierPickerMenu extends PureComponent {
 
   static propTypes = {
     active: PropTypes.bool,
@@ -59,7 +59,7 @@ class ModifierPickerMenu extends React.PureComponent {
     this.props.onSelect(e.currentTarget.getAttribute('data-index') * 1);
   }
 
-  componentWillReceiveProps (nextProps) {
+  UNSAFE_componentWillReceiveProps (nextProps) {
     if (nextProps.active) {
       this.attachListeners();
     } else {
@@ -108,7 +108,7 @@ class ModifierPickerMenu extends React.PureComponent {
 
 }
 
-class ModifierPicker extends React.PureComponent {
+class ModifierPicker extends PureComponent {
 
   static propTypes = {
     active: PropTypes.bool,
@@ -145,7 +145,7 @@ class ModifierPicker extends React.PureComponent {
 }
 
 @injectIntl
-class EmojiPickerMenu extends React.PureComponent {
+class EmojiPickerMenu extends PureComponent {
 
   static propTypes = {
     custom_emojis: ImmutablePropTypes.list,
@@ -309,7 +309,7 @@ class EmojiPickerMenu extends React.PureComponent {
 }
 
 export default @injectIntl
-class EmojiPickerDropdown extends React.PureComponent {
+class EmojiPickerDropdown extends PureComponent {
 
   static propTypes = {
     custom_emojis: ImmutablePropTypes.list,
diff --git a/app/javascript/mastodon/features/compose/components/language_dropdown.js b/app/javascript/mastodon/features/compose/components/language_dropdown.js
index d76490c775f..084980de8ce 100644
--- a/app/javascript/mastodon/features/compose/components/language_dropdown.js
+++ b/app/javascript/mastodon/features/compose/components/language_dropdown.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import { injectIntl, defineMessages } from 'react-intl';
 import TextIconButton from './text_icon_button';
@@ -34,7 +34,7 @@ const icons = {
 
 const listenerOptions = supportsPassiveEvents ? { passive: true } : false;
 
-class LanguageDropdownMenu extends React.PureComponent {
+class LanguageDropdownMenu extends PureComponent {
 
   static propTypes = {
     style: PropTypes.object,
@@ -257,7 +257,7 @@ class LanguageDropdownMenu extends React.PureComponent {
 }
 
 export default @injectIntl
-class LanguageDropdown extends React.PureComponent {
+class LanguageDropdown extends PureComponent {
 
   static propTypes = {
     value: PropTypes.string,
diff --git a/app/javascript/mastodon/features/compose/components/navigation_bar.js b/app/javascript/mastodon/features/compose/components/navigation_bar.js
index e6ba7d8b73d..684e00a340e 100644
--- a/app/javascript/mastodon/features/compose/components/navigation_bar.js
+++ b/app/javascript/mastodon/features/compose/components/navigation_bar.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import ActionBar from './action_bar';
diff --git a/app/javascript/mastodon/features/compose/components/poll_button.js b/app/javascript/mastodon/features/compose/components/poll_button.js
index 76f96bfa41e..22192778442 100644
--- a/app/javascript/mastodon/features/compose/components/poll_button.js
+++ b/app/javascript/mastodon/features/compose/components/poll_button.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import IconButton from '../../../components/icon_button';
 import PropTypes from 'prop-types';
 import { defineMessages, injectIntl } from 'react-intl';
@@ -15,7 +15,7 @@ const iconStyle = {
 
 export default
 @injectIntl
-class PollButton extends React.PureComponent {
+class PollButton extends PureComponent {
 
   static propTypes = {
     disabled: PropTypes.bool,
diff --git a/app/javascript/mastodon/features/compose/components/poll_form.js b/app/javascript/mastodon/features/compose/components/poll_form.js
index db49f90eb4c..59891b78837 100644
--- a/app/javascript/mastodon/features/compose/components/poll_form.js
+++ b/app/javascript/mastodon/features/compose/components/poll_form.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import ImmutablePureComponent from 'react-immutable-pure-component';
@@ -21,7 +21,7 @@ const messages = defineMessages({
 });
 
 @injectIntl
-class Option extends React.PureComponent {
+class Option extends PureComponent {
 
   static propTypes = {
     title: PropTypes.string.isRequired,
diff --git a/app/javascript/mastodon/features/compose/components/privacy_dropdown.js b/app/javascript/mastodon/features/compose/components/privacy_dropdown.js
index 1f0e998d36f..dc7ef674d83 100644
--- a/app/javascript/mastodon/features/compose/components/privacy_dropdown.js
+++ b/app/javascript/mastodon/features/compose/components/privacy_dropdown.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import { injectIntl, defineMessages } from 'react-intl';
 import IconButton from '../../../components/icon_button';
@@ -23,7 +23,7 @@ const messages = defineMessages({
 
 const listenerOptions = supportsPassiveEvents ? { passive: true } : false;
 
-class PrivacyDropdownMenu extends React.PureComponent {
+class PrivacyDropdownMenu extends PureComponent {
 
   static propTypes = {
     style: PropTypes.object,
@@ -149,7 +149,7 @@ class PrivacyDropdownMenu extends React.PureComponent {
 }
 
 export default @injectIntl
-class PrivacyDropdown extends React.PureComponent {
+class PrivacyDropdown extends PureComponent {
 
   static propTypes = {
     isUserTouching: PropTypes.func,
@@ -231,7 +231,7 @@ class PrivacyDropdown extends React.PureComponent {
     this.props.onChange(value);
   }
 
-  componentWillMount () {
+  UNSAFE_componentWillMount () {
     const { intl: { formatMessage } } = this.props;
 
     this.options = [
diff --git a/app/javascript/mastodon/features/compose/components/reply_indicator.js b/app/javascript/mastodon/features/compose/components/reply_indicator.js
index 863defb768f..051de00be71 100644
--- a/app/javascript/mastodon/features/compose/components/reply_indicator.js
+++ b/app/javascript/mastodon/features/compose/components/reply_indicator.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
 import Avatar from '../../../components/avatar';
diff --git a/app/javascript/mastodon/features/compose/components/search.js b/app/javascript/mastodon/features/compose/components/search.js
index 3e36a922be6..383781bf5be 100644
--- a/app/javascript/mastodon/features/compose/components/search.js
+++ b/app/javascript/mastodon/features/compose/components/search.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 import Overlay from 'react-overlays/lib/Overlay';
@@ -11,7 +11,7 @@ const messages = defineMessages({
   placeholder: { id: 'search.placeholder', defaultMessage: 'Search' },
 });
 
-class SearchPopout extends React.PureComponent {
+class SearchPopout extends PureComponent {
 
   static propTypes = {
     style: PropTypes.object,
@@ -45,7 +45,7 @@ class SearchPopout extends React.PureComponent {
 }
 
 export default @injectIntl
-class Search extends React.PureComponent {
+class Search extends PureComponent {
 
   static contextTypes = {
     router: PropTypes.object.isRequired,
diff --git a/app/javascript/mastodon/features/compose/components/search_results.js b/app/javascript/mastodon/features/compose/components/search_results.js
index e2493a6c6ab..81289025db8 100644
--- a/app/javascript/mastodon/features/compose/components/search_results.js
+++ b/app/javascript/mastodon/features/compose/components/search_results.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
diff --git a/app/javascript/mastodon/features/compose/components/text_icon_button.js b/app/javascript/mastodon/features/compose/components/text_icon_button.js
index cd644b680e9..6350001eee8 100644
--- a/app/javascript/mastodon/features/compose/components/text_icon_button.js
+++ b/app/javascript/mastodon/features/compose/components/text_icon_button.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 
 const iconStyle = {
@@ -7,7 +7,7 @@ const iconStyle = {
   width: `${18 * 1.28571429}px`,
 };
 
-export default class TextIconButton extends React.PureComponent {
+export default class TextIconButton extends PureComponent {
 
   static propTypes = {
     label: PropTypes.string.isRequired,
diff --git a/app/javascript/mastodon/features/compose/components/upload.js b/app/javascript/mastodon/features/compose/components/upload.js
index 706824dc712..c9a934398d2 100644
--- a/app/javascript/mastodon/features/compose/components/upload.js
+++ b/app/javascript/mastodon/features/compose/components/upload.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
 import Motion from '../../ui/util/optional_motion';
diff --git a/app/javascript/mastodon/features/compose/components/upload_button.js b/app/javascript/mastodon/features/compose/components/upload_button.js
index 9cb36167a86..e2756fcf86b 100644
--- a/app/javascript/mastodon/features/compose/components/upload_button.js
+++ b/app/javascript/mastodon/features/compose/components/upload_button.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import IconButton from '../../../components/icon_button';
 import PropTypes from 'prop-types';
 import { defineMessages, injectIntl } from 'react-intl';
diff --git a/app/javascript/mastodon/features/compose/components/upload_form.js b/app/javascript/mastodon/features/compose/components/upload_form.js
index c6eac554e6c..b07bdbbd64b 100644
--- a/app/javascript/mastodon/features/compose/components/upload_form.js
+++ b/app/javascript/mastodon/features/compose/components/upload_form.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import UploadProgressContainer from '../containers/upload_progress_container';
 import ImmutablePureComponent from 'react-immutable-pure-component';
diff --git a/app/javascript/mastodon/features/compose/components/upload_progress.js b/app/javascript/mastodon/features/compose/components/upload_progress.js
index b0bfe0c9a14..5d92e6ed281 100644
--- a/app/javascript/mastodon/features/compose/components/upload_progress.js
+++ b/app/javascript/mastodon/features/compose/components/upload_progress.js
@@ -1,10 +1,10 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import Motion from '../../ui/util/optional_motion';
 import spring from 'react-motion/lib/spring';
 import Icon from 'mastodon/components/icon';
 
-export default class UploadProgress extends React.PureComponent {
+export default class UploadProgress extends PureComponent {
 
   static propTypes = {
     active: PropTypes.bool,
diff --git a/app/javascript/mastodon/features/compose/components/warning.js b/app/javascript/mastodon/features/compose/components/warning.js
index 803b7f86abd..4947a4e28b9 100644
--- a/app/javascript/mastodon/features/compose/components/warning.js
+++ b/app/javascript/mastodon/features/compose/components/warning.js
@@ -1,9 +1,9 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import Motion from '../../ui/util/optional_motion';
 import spring from 'react-motion/lib/spring';
 
-export default class Warning extends React.PureComponent {
+export default class Warning extends PureComponent {
 
   static propTypes = {
     message: PropTypes.node.isRequired,
diff --git a/app/javascript/mastodon/features/compose/containers/sensitive_button_container.js b/app/javascript/mastodon/features/compose/containers/sensitive_button_container.js
index 1bcce57310a..2a99b2620cf 100644
--- a/app/javascript/mastodon/features/compose/containers/sensitive_button_container.js
+++ b/app/javascript/mastodon/features/compose/containers/sensitive_button_container.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import { connect } from 'react-redux';
 import PropTypes from 'prop-types';
 import classNames from 'classnames';
@@ -30,7 +30,7 @@ const mapDispatchToProps = dispatch => ({
 
 });
 
-class SensitiveButton extends React.PureComponent {
+class SensitiveButton extends PureComponent {
 
   static propTypes = {
     active: PropTypes.bool,
diff --git a/app/javascript/mastodon/features/compose/containers/warning_container.js b/app/javascript/mastodon/features/compose/containers/warning_container.js
index 571d1d83826..76653f7abe8 100644
--- a/app/javascript/mastodon/features/compose/containers/warning_container.js
+++ b/app/javascript/mastodon/features/compose/containers/warning_container.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import { connect } from 'react-redux';
 import Warning from '../components/warning';
 import PropTypes from 'prop-types';
diff --git a/app/javascript/mastodon/features/compose/index.js b/app/javascript/mastodon/features/compose/index.js
index 711a5590460..c11043a45d5 100644
--- a/app/javascript/mastodon/features/compose/index.js
+++ b/app/javascript/mastodon/features/compose/index.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import ComposeFormContainer from './containers/compose_form_container';
 import NavigationContainer from './containers/navigation_container';
 import PropTypes from 'prop-types';
@@ -38,7 +38,7 @@ const mapStateToProps = (state, ownProps) => ({
 
 export default @connect(mapStateToProps)
 @injectIntl
-class Compose extends React.PureComponent {
+class Compose extends PureComponent {
 
   static propTypes = {
     dispatch: PropTypes.func.isRequired,
diff --git a/app/javascript/mastodon/features/direct_timeline/components/conversation.js b/app/javascript/mastodon/features/direct_timeline/components/conversation.js
index 77ff2ce7b3b..6d6d8c3c6cf 100644
--- a/app/javascript/mastodon/features/direct_timeline/components/conversation.js
+++ b/app/javascript/mastodon/features/direct_timeline/components/conversation.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import ImmutablePureComponent from 'react-immutable-pure-component';
diff --git a/app/javascript/mastodon/features/direct_timeline/components/conversations_list.js b/app/javascript/mastodon/features/direct_timeline/components/conversations_list.js
index fd1df725689..55426828584 100644
--- a/app/javascript/mastodon/features/direct_timeline/components/conversations_list.js
+++ b/app/javascript/mastodon/features/direct_timeline/components/conversations_list.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import ImmutablePureComponent from 'react-immutable-pure-component';
diff --git a/app/javascript/mastodon/features/direct_timeline/index.js b/app/javascript/mastodon/features/direct_timeline/index.js
index debb2d721c8..1686ecccd2d 100644
--- a/app/javascript/mastodon/features/direct_timeline/index.js
+++ b/app/javascript/mastodon/features/direct_timeline/index.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import { connect } from 'react-redux';
 import PropTypes from 'prop-types';
 import Column from '../../components/column';
@@ -15,7 +15,7 @@ const messages = defineMessages({
 
 export default @connect()
 @injectIntl
-class DirectTimeline extends React.PureComponent {
+class DirectTimeline extends PureComponent {
 
   static propTypes = {
     dispatch: PropTypes.func.isRequired,
diff --git a/app/javascript/mastodon/features/directory/components/account_card.js b/app/javascript/mastodon/features/directory/components/account_card.js
index 27ba4e7f405..87a664d552e 100644
--- a/app/javascript/mastodon/features/directory/components/account_card.js
+++ b/app/javascript/mastodon/features/directory/components/account_card.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
diff --git a/app/javascript/mastodon/features/directory/index.js b/app/javascript/mastodon/features/directory/index.js
index 94d7d1a9c54..9e8090dfdf0 100644
--- a/app/javascript/mastodon/features/directory/index.js
+++ b/app/javascript/mastodon/features/directory/index.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import { connect } from 'react-redux';
 import { defineMessages, injectIntl } from 'react-intl';
 import PropTypes from 'prop-types';
@@ -30,7 +30,7 @@ const mapStateToProps = state => ({
 
 export default @connect(mapStateToProps)
 @injectIntl
-class Directory extends React.PureComponent {
+class Directory extends PureComponent {
 
   static contextTypes = {
     router: PropTypes.object,
diff --git a/app/javascript/mastodon/features/domain_blocks/index.js b/app/javascript/mastodon/features/domain_blocks/index.js
index edb80aef410..03c9b31b680 100644
--- a/app/javascript/mastodon/features/domain_blocks/index.js
+++ b/app/javascript/mastodon/features/domain_blocks/index.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import { connect } from 'react-redux';
 import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 import ImmutablePureComponent from 'react-immutable-pure-component';
@@ -35,7 +34,7 @@ class Blocks extends ImmutablePureComponent {
     multiColumn: PropTypes.bool,
   };
 
-  componentWillMount () {
+  UNSAFE_componentWillMount () {
     this.props.dispatch(fetchDomainBlocks());
   }
 
diff --git a/app/javascript/mastodon/features/explore/components/story.js b/app/javascript/mastodon/features/explore/components/story.js
index 56312802970..977d9eea80f 100644
--- a/app/javascript/mastodon/features/explore/components/story.js
+++ b/app/javascript/mastodon/features/explore/components/story.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import Blurhash from 'mastodon/components/blurhash';
 import { accountsCountRenderer } from 'mastodon/components/hashtag';
@@ -6,7 +6,7 @@ import ShortNumber from 'mastodon/components/short_number';
 import Skeleton from 'mastodon/components/skeleton';
 import classNames from 'classnames';
 
-export default class Story extends React.PureComponent {
+export default class Story extends PureComponent {
 
   static propTypes = {
     url: PropTypes.string,
@@ -38,10 +38,10 @@ export default class Story extends React.PureComponent {
 
         <div className='story__thumbnail'>
           {thumbnail ? (
-            <React.Fragment>
+            <>
               <div className={classNames('story__thumbnail__preview', { 'story__thumbnail__preview--hidden': thumbnailLoaded })}><Blurhash hash={blurhash} /></div>
               <img src={thumbnail} onLoad={this.handleImageLoad} alt='' role='presentation' />
-            </React.Fragment>
+            </>
           ) : <Skeleton />}
         </div>
       </a>
diff --git a/app/javascript/mastodon/features/explore/index.js b/app/javascript/mastodon/features/explore/index.js
index 8082f2d99cb..18275f868bb 100644
--- a/app/javascript/mastodon/features/explore/index.js
+++ b/app/javascript/mastodon/features/explore/index.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 import { connect } from 'react-redux';
 import PropTypes from 'prop-types';
@@ -24,7 +24,7 @@ const mapStateToProps = state => ({
 
 export default @connect(mapStateToProps)
 @injectIntl
-class Explore extends React.PureComponent {
+class Explore extends PureComponent {
 
   static contextTypes = {
     router: PropTypes.object,
@@ -67,7 +67,7 @@ class Explore extends React.PureComponent {
           {isSearching ? (
             <SearchResults />
           ) : (
-            <React.Fragment>
+            <>
               <div className='account__section-headline'>
                 <NavLink exact to='/explore'><FormattedMessage id='explore.trending_statuses' defaultMessage='Posts' /></NavLink>
                 <NavLink exact to='/explore/tags'><FormattedMessage id='explore.trending_tags' defaultMessage='Hashtags' /></NavLink>
@@ -81,7 +81,7 @@ class Explore extends React.PureComponent {
                 <Route path='/explore/suggestions' component={Suggestions} />
                 <Route exact path={['/explore', '/explore/posts', '/search']} component={Statuses} componentParams={{ multiColumn }} />
               </Switch>
-            </React.Fragment>
+            </>
           )}
         </div>
       </Column>
diff --git a/app/javascript/mastodon/features/explore/links.js b/app/javascript/mastodon/features/explore/links.js
index 6649fb6e471..c7fc2c33311 100644
--- a/app/javascript/mastodon/features/explore/links.js
+++ b/app/javascript/mastodon/features/explore/links.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import Story from './components/story';
@@ -12,7 +12,7 @@ const mapStateToProps = state => ({
 });
 
 export default @connect(mapStateToProps)
-class Links extends React.PureComponent {
+class Links extends PureComponent {
 
   static propTypes = {
     links: ImmutablePropTypes.list,
diff --git a/app/javascript/mastodon/features/explore/results.js b/app/javascript/mastodon/features/explore/results.js
index 1286020f54c..1a784367095 100644
--- a/app/javascript/mastodon/features/explore/results.js
+++ b/app/javascript/mastodon/features/explore/results.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import { FormattedMessage } from 'react-intl';
@@ -37,7 +37,7 @@ const renderStatuses = (results, onLoadMore) => appendLoadMore('statuses', resul
 )), onLoadMore);
 
 export default @connect(mapStateToProps)
-class Results extends React.PureComponent {
+class Results extends PureComponent {
 
   static propTypes = {
     results: ImmutablePropTypes.map,
@@ -95,7 +95,7 @@ class Results extends React.PureComponent {
     }
 
     return (
-      <React.Fragment>
+      <>
         <div className='account__section-headline'>
           <button onClick={this.handleSelectAll} className={type === 'all' && 'active'}><FormattedMessage id='search_results.all' defaultMessage='All' /></button>
           <button onClick={this.handleSelectAccounts} className={type === 'accounts' && 'active'}><FormattedMessage id='search_results.accounts' defaultMessage='People' /></button>
@@ -106,7 +106,7 @@ class Results extends React.PureComponent {
         <div className='explore__search-results'>
           {isLoading ? <LoadingIndicator /> : filteredResults}
         </div>
-      </React.Fragment>
+      </>
     );
   }
 
diff --git a/app/javascript/mastodon/features/explore/statuses.js b/app/javascript/mastodon/features/explore/statuses.js
index 33e5b417964..023f31264a1 100644
--- a/app/javascript/mastodon/features/explore/statuses.js
+++ b/app/javascript/mastodon/features/explore/statuses.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import StatusList from 'mastodon/components/status_list';
@@ -14,7 +14,7 @@ const mapStateToProps = state => ({
 });
 
 export default @connect(mapStateToProps)
-class Statuses extends React.PureComponent {
+class Statuses extends PureComponent {
 
   static propTypes = {
     statusIds: ImmutablePropTypes.list,
diff --git a/app/javascript/mastodon/features/explore/suggestions.js b/app/javascript/mastodon/features/explore/suggestions.js
index 0c6a7ef8a3b..f8ea7e1f958 100644
--- a/app/javascript/mastodon/features/explore/suggestions.js
+++ b/app/javascript/mastodon/features/explore/suggestions.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import AccountCard from 'mastodon/features/directory/components/account_card';
@@ -12,7 +12,7 @@ const mapStateToProps = state => ({
 });
 
 export default @connect(mapStateToProps)
-class Suggestions extends React.PureComponent {
+class Suggestions extends PureComponent {
 
   static propTypes = {
     isLoading: PropTypes.bool,
diff --git a/app/javascript/mastodon/features/explore/tags.js b/app/javascript/mastodon/features/explore/tags.js
index c0ad9fc6ec9..50f7e7f03a7 100644
--- a/app/javascript/mastodon/features/explore/tags.js
+++ b/app/javascript/mastodon/features/explore/tags.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import { ImmutableHashtag as Hashtag } from 'mastodon/components/hashtag';
@@ -12,7 +12,7 @@ const mapStateToProps = state => ({
 });
 
 export default @connect(mapStateToProps)
-class Tags extends React.PureComponent {
+class Tags extends PureComponent {
 
   static propTypes = {
     hashtags: ImmutablePropTypes.list,
diff --git a/app/javascript/mastodon/features/favourited_statuses/index.js b/app/javascript/mastodon/features/favourited_statuses/index.js
index 73631946a7b..db5157a565d 100644
--- a/app/javascript/mastodon/features/favourited_statuses/index.js
+++ b/app/javascript/mastodon/features/favourited_statuses/index.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import { connect } from 'react-redux';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
@@ -35,7 +34,7 @@ class Favourites extends ImmutablePureComponent {
     isLoading: PropTypes.bool,
   };
 
-  componentWillMount () {
+  UNSAFE_componentWillMount () {
     this.props.dispatch(fetchFavouritedStatuses());
   }
 
diff --git a/app/javascript/mastodon/features/favourites/index.js b/app/javascript/mastodon/features/favourites/index.js
index f060068a49b..0452e285a97 100644
--- a/app/javascript/mastodon/features/favourites/index.js
+++ b/app/javascript/mastodon/features/favourites/index.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import { connect } from 'react-redux';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import PropTypes from 'prop-types';
@@ -32,13 +31,13 @@ class Favourites extends ImmutablePureComponent {
     intl: PropTypes.object.isRequired,
   };
 
-  componentWillMount () {
+  UNSAFE_componentWillMount () {
     if (!this.props.accountIds) {
       this.props.dispatch(fetchFavourites(this.props.params.statusId));
     }
   }
 
-  componentWillReceiveProps (nextProps) {
+  UNSAFE_componentWillReceiveProps (nextProps) {
     if (nextProps.params.statusId !== this.props.params.statusId && nextProps.params.statusId) {
       this.props.dispatch(fetchFavourites(nextProps.params.statusId));
     }
diff --git a/app/javascript/mastodon/features/follow_recommendations/components/account.js b/app/javascript/mastodon/features/follow_recommendations/components/account.js
index ffc0ab00cc2..5beccef6d1a 100644
--- a/app/javascript/mastodon/features/follow_recommendations/components/account.js
+++ b/app/javascript/mastodon/features/follow_recommendations/components/account.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import ImmutablePureComponent from 'react-immutable-pure-component';
diff --git a/app/javascript/mastodon/features/follow_recommendations/index.js b/app/javascript/mastodon/features/follow_recommendations/index.js
index b5a71aef5b3..6b210dfd322 100644
--- a/app/javascript/mastodon/features/follow_recommendations/index.js
+++ b/app/javascript/mastodon/features/follow_recommendations/index.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import ImmutablePropTypes from 'react-immutable-proptypes';
@@ -84,7 +83,7 @@ class FollowRecommendations extends ImmutablePureComponent {
           </div>
 
           {!isLoading && (
-            <React.Fragment>
+            <>
               <div className='column-list'>
                 {suggestions.size > 0 ? suggestions.map(suggestion => (
                   <Account key={suggestion.get('account')} id={suggestion.get('account')} />
@@ -99,7 +98,7 @@ class FollowRecommendations extends ImmutablePureComponent {
                 <img src={imageGreeting} alt='' className='column-actions__background' />
                 <Button onClick={this.handleDone}><FormattedMessage id='follow_recommendations.done' defaultMessage='Done' /></Button>
               </div>
-            </React.Fragment>
+            </>
           )}
         </div>
       </Column>
diff --git a/app/javascript/mastodon/features/follow_requests/components/account_authorize.js b/app/javascript/mastodon/features/follow_requests/components/account_authorize.js
index 263a7ae1626..bb81cfb2e2f 100644
--- a/app/javascript/mastodon/features/follow_requests/components/account_authorize.js
+++ b/app/javascript/mastodon/features/follow_requests/components/account_authorize.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import Permalink from '../../../components/permalink';
diff --git a/app/javascript/mastodon/features/follow_requests/index.js b/app/javascript/mastodon/features/follow_requests/index.js
index 1f9b635bb78..68396645bc8 100644
--- a/app/javascript/mastodon/features/follow_requests/index.js
+++ b/app/javascript/mastodon/features/follow_requests/index.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import { connect } from 'react-redux';
 import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 import ImmutablePureComponent from 'react-immutable-pure-component';
@@ -41,7 +40,7 @@ class FollowRequests extends ImmutablePureComponent {
     multiColumn: PropTypes.bool,
   };
 
-  componentWillMount () {
+  UNSAFE_componentWillMount () {
     this.props.dispatch(fetchFollowRequests());
   }
 
diff --git a/app/javascript/mastodon/features/followers/index.js b/app/javascript/mastodon/features/followers/index.js
index 5b7f402f8d9..d180b96dd6e 100644
--- a/app/javascript/mastodon/features/followers/index.js
+++ b/app/javascript/mastodon/features/followers/index.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import { connect } from 'react-redux';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import PropTypes from 'prop-types';
diff --git a/app/javascript/mastodon/features/following/index.js b/app/javascript/mastodon/features/following/index.js
index 143082d760a..a400d79c8e4 100644
--- a/app/javascript/mastodon/features/following/index.js
+++ b/app/javascript/mastodon/features/following/index.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import { connect } from 'react-redux';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import PropTypes from 'prop-types';
diff --git a/app/javascript/mastodon/features/generic_not_found/index.js b/app/javascript/mastodon/features/generic_not_found/index.js
index 41cd61a5f8b..c7f82626e61 100644
--- a/app/javascript/mastodon/features/generic_not_found/index.js
+++ b/app/javascript/mastodon/features/generic_not_found/index.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import Column from '../ui/components/column';
 import MissingIndicator from '../../components/missing_indicator';
 
diff --git a/app/javascript/mastodon/features/getting_started/components/announcements.js b/app/javascript/mastodon/features/getting_started/components/announcements.js
index 24db8cedec6..567ce4ba5fe 100644
--- a/app/javascript/mastodon/features/getting_started/components/announcements.js
+++ b/app/javascript/mastodon/features/getting_started/components/announcements.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import ReactSwipeableViews from 'react-swipeable-views';
 import ImmutablePropTypes from 'react-immutable-proptypes';
@@ -149,7 +149,7 @@ class Content extends ImmutablePureComponent {
 
 }
 
-class Emoji extends React.PureComponent {
+class Emoji extends PureComponent {
 
   static propTypes = {
     emoji: PropTypes.string.isRequired,
diff --git a/app/javascript/mastodon/features/getting_started/components/trends.js b/app/javascript/mastodon/features/getting_started/components/trends.js
index 71c7c458dca..4ea812901de 100644
--- a/app/javascript/mastodon/features/getting_started/components/trends.js
+++ b/app/javascript/mastodon/features/getting_started/components/trends.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
diff --git a/app/javascript/mastodon/features/getting_started/index.js b/app/javascript/mastodon/features/getting_started/index.js
index 65cee7498b7..e58f7b63c77 100644
--- a/app/javascript/mastodon/features/getting_started/index.js
+++ b/app/javascript/mastodon/features/getting_started/index.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import Column from '../ui/components/column';
 import ColumnLink from '../ui/components/column_link';
 import ColumnSubheading from '../ui/components/column_subheading';
diff --git a/app/javascript/mastodon/features/hashtag_timeline/components/column_settings.js b/app/javascript/mastodon/features/hashtag_timeline/components/column_settings.js
index ede8907e50b..c375d585ed6 100644
--- a/app/javascript/mastodon/features/hashtag_timeline/components/column_settings.js
+++ b/app/javascript/mastodon/features/hashtag_timeline/components/column_settings.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
@@ -13,7 +13,7 @@ const messages = defineMessages({
 });
 
 export default @injectIntl
-class ColumnSettings extends React.PureComponent {
+class ColumnSettings extends PureComponent {
 
   static propTypes = {
     settings: ImmutablePropTypes.map.isRequired,
diff --git a/app/javascript/mastodon/features/hashtag_timeline/index.js b/app/javascript/mastodon/features/hashtag_timeline/index.js
index 6a808eb306c..10b3358ce2f 100644
--- a/app/javascript/mastodon/features/hashtag_timeline/index.js
+++ b/app/javascript/mastodon/features/hashtag_timeline/index.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import { connect } from 'react-redux';
 import PropTypes from 'prop-types';
 import StatusListContainer from '../ui/containers/status_list_container';
@@ -16,7 +16,7 @@ const mapStateToProps = (state, props) => ({
 });
 
 export default @connect(mapStateToProps)
-class HashtagTimeline extends React.PureComponent {
+class HashtagTimeline extends PureComponent {
 
   disconnects = [];
 
@@ -103,7 +103,7 @@ class HashtagTimeline extends React.PureComponent {
     dispatch(expandHashtagTimeline(id, { tags, local }));
   }
 
-  componentWillReceiveProps (nextProps) {
+  UNSAFE_componentWillReceiveProps (nextProps) {
     const { dispatch, params } = this.props;
     const { id, tags, local } = nextProps.params;
 
diff --git a/app/javascript/mastodon/features/home_timeline/components/column_settings.js b/app/javascript/mastodon/features/home_timeline/components/column_settings.js
index 455e218817c..490ae99b457 100644
--- a/app/javascript/mastodon/features/home_timeline/components/column_settings.js
+++ b/app/javascript/mastodon/features/home_timeline/components/column_settings.js
@@ -1,11 +1,11 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import { injectIntl, FormattedMessage } from 'react-intl';
 import SettingToggle from '../../notifications/components/setting_toggle';
 
 export default @injectIntl
-class ColumnSettings extends React.PureComponent {
+class ColumnSettings extends PureComponent {
 
   static propTypes = {
     settings: ImmutablePropTypes.map.isRequired,
diff --git a/app/javascript/mastodon/features/home_timeline/index.js b/app/javascript/mastodon/features/home_timeline/index.js
index dc440f2fe00..ff04ddfb384 100644
--- a/app/javascript/mastodon/features/home_timeline/index.js
+++ b/app/javascript/mastodon/features/home_timeline/index.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import { connect } from 'react-redux';
 import { expandHomeTimeline } from '../../actions/timelines';
 import PropTypes from 'prop-types';
@@ -30,7 +30,7 @@ const mapStateToProps = state => ({
 
 export default @connect(mapStateToProps)
 @injectIntl
-class HomeTimeline extends React.PureComponent {
+class HomeTimeline extends PureComponent {
 
   static propTypes = {
     dispatch: PropTypes.func.isRequired,
diff --git a/app/javascript/mastodon/features/keyboard_shortcuts/index.js b/app/javascript/mastodon/features/keyboard_shortcuts/index.js
index 8f1631d8295..3072c5d38c7 100644
--- a/app/javascript/mastodon/features/keyboard_shortcuts/index.js
+++ b/app/javascript/mastodon/features/keyboard_shortcuts/index.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import Column from '../ui/components/column';
 import ColumnBackButtonSlim from '../../components/column_back_button_slim';
 import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
diff --git a/app/javascript/mastodon/features/list_adder/components/account.js b/app/javascript/mastodon/features/list_adder/components/account.js
index 1369aac0742..c3468a930e2 100644
--- a/app/javascript/mastodon/features/list_adder/components/account.js
+++ b/app/javascript/mastodon/features/list_adder/components/account.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import { connect } from 'react-redux';
 import { makeGetAccount } from '../../../selectors';
 import ImmutablePureComponent from 'react-immutable-pure-component';
diff --git a/app/javascript/mastodon/features/list_adder/components/list.js b/app/javascript/mastodon/features/list_adder/components/list.js
index 60c8958a737..88458856dc4 100644
--- a/app/javascript/mastodon/features/list_adder/components/list.js
+++ b/app/javascript/mastodon/features/list_adder/components/list.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import PropTypes from 'prop-types';
 import { connect } from 'react-redux';
 import ImmutablePureComponent from 'react-immutable-pure-component';
diff --git a/app/javascript/mastodon/features/list_adder/index.js b/app/javascript/mastodon/features/list_adder/index.js
index cb8a15e8c7d..f3e34159005 100644
--- a/app/javascript/mastodon/features/list_adder/index.js
+++ b/app/javascript/mastodon/features/list_adder/index.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import { connect } from 'react-redux';
diff --git a/app/javascript/mastodon/features/list_editor/components/account.js b/app/javascript/mastodon/features/list_editor/components/account.js
index 48085af43d1..22b41ce81ac 100644
--- a/app/javascript/mastodon/features/list_editor/components/account.js
+++ b/app/javascript/mastodon/features/list_editor/components/account.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import PropTypes from 'prop-types';
 import { connect } from 'react-redux';
 import { makeGetAccount } from '../../../selectors';
diff --git a/app/javascript/mastodon/features/list_editor/components/edit_list_form.js b/app/javascript/mastodon/features/list_editor/components/edit_list_form.js
index 3ccab12a800..f092a5aa26e 100644
--- a/app/javascript/mastodon/features/list_editor/components/edit_list_form.js
+++ b/app/javascript/mastodon/features/list_editor/components/edit_list_form.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import { connect } from 'react-redux';
 import PropTypes from 'prop-types';
 import { changeListEditorTitle, submitListEditor } from '../../../actions/lists';
@@ -21,7 +21,7 @@ const mapDispatchToProps = dispatch => ({
 
 export default @connect(mapStateToProps, mapDispatchToProps)
 @injectIntl
-class ListForm extends React.PureComponent {
+class ListForm extends PureComponent {
 
   static propTypes = {
     value: PropTypes.string.isRequired,
diff --git a/app/javascript/mastodon/features/list_editor/components/search.js b/app/javascript/mastodon/features/list_editor/components/search.js
index e3f069bb807..721fffb0218 100644
--- a/app/javascript/mastodon/features/list_editor/components/search.js
+++ b/app/javascript/mastodon/features/list_editor/components/search.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import { connect } from 'react-redux';
 import { defineMessages, injectIntl } from 'react-intl';
@@ -22,7 +22,7 @@ const mapDispatchToProps = dispatch => ({
 
 export default @connect(mapStateToProps, mapDispatchToProps)
 @injectIntl
-class Search extends React.PureComponent {
+class Search extends PureComponent {
 
   static propTypes = {
     intl: PropTypes.object.isRequired,
diff --git a/app/javascript/mastodon/features/list_editor/index.js b/app/javascript/mastodon/features/list_editor/index.js
index 48466604a7d..0e68637f38c 100644
--- a/app/javascript/mastodon/features/list_editor/index.js
+++ b/app/javascript/mastodon/features/list_editor/index.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import { connect } from 'react-redux';
diff --git a/app/javascript/mastodon/features/list_timeline/index.js b/app/javascript/mastodon/features/list_timeline/index.js
index 8010274f880..91fbfeceef9 100644
--- a/app/javascript/mastodon/features/list_timeline/index.js
+++ b/app/javascript/mastodon/features/list_timeline/index.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import { connect } from 'react-redux';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
@@ -32,7 +32,7 @@ const mapStateToProps = (state, props) => ({
 
 export default @connect(mapStateToProps)
 @injectIntl
-class ListTimeline extends React.PureComponent {
+class ListTimeline extends PureComponent {
 
   static contextTypes = {
     router: PropTypes.object,
@@ -78,7 +78,7 @@ class ListTimeline extends React.PureComponent {
     this.disconnect = dispatch(connectListStream(id));
   }
 
-  componentWillReceiveProps (nextProps) {
+  UNSAFE_componentWillReceiveProps (nextProps) {
     const { dispatch } = this.props;
     const { id } = nextProps.params;
 
diff --git a/app/javascript/mastodon/features/lists/components/new_list_form.js b/app/javascript/mastodon/features/lists/components/new_list_form.js
index 7faf50be81c..acc2d8216e9 100644
--- a/app/javascript/mastodon/features/lists/components/new_list_form.js
+++ b/app/javascript/mastodon/features/lists/components/new_list_form.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import { connect } from 'react-redux';
 import PropTypes from 'prop-types';
 import { changeListEditorTitle, submitListEditor } from '../../../actions/lists';
@@ -22,7 +22,7 @@ const mapDispatchToProps = dispatch => ({
 
 export default @connect(mapStateToProps, mapDispatchToProps)
 @injectIntl
-class NewListForm extends React.PureComponent {
+class NewListForm extends PureComponent {
 
   static propTypes = {
     value: PropTypes.string.isRequired,
diff --git a/app/javascript/mastodon/features/lists/index.js b/app/javascript/mastodon/features/lists/index.js
index 809d79d9981..de6c8dca1a6 100644
--- a/app/javascript/mastodon/features/lists/index.js
+++ b/app/javascript/mastodon/features/lists/index.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import { connect } from 'react-redux';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
@@ -43,7 +42,7 @@ class Lists extends ImmutablePureComponent {
     multiColumn: PropTypes.bool,
   };
 
-  componentWillMount () {
+  UNSAFE_componentWillMount () {
     this.props.dispatch(fetchLists());
   }
 
diff --git a/app/javascript/mastodon/features/mutes/index.js b/app/javascript/mastodon/features/mutes/index.js
index c21433cc414..75cd1d73d28 100644
--- a/app/javascript/mastodon/features/mutes/index.js
+++ b/app/javascript/mastodon/features/mutes/index.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import { connect } from 'react-redux';
 import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 import ImmutablePureComponent from 'react-immutable-pure-component';
@@ -36,7 +35,7 @@ class Mutes extends ImmutablePureComponent {
     multiColumn: PropTypes.bool,
   };
 
-  componentWillMount () {
+  UNSAFE_componentWillMount () {
     this.props.dispatch(fetchMutes());
   }
 
diff --git a/app/javascript/mastodon/features/notifications/components/clear_column_button.js b/app/javascript/mastodon/features/notifications/components/clear_column_button.js
index b82fd092f8e..3d73625fe2c 100644
--- a/app/javascript/mastodon/features/notifications/components/clear_column_button.js
+++ b/app/javascript/mastodon/features/notifications/components/clear_column_button.js
@@ -1,9 +1,9 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import { FormattedMessage } from 'react-intl';
 import Icon from 'mastodon/components/icon';
 
-export default class ClearColumnButton extends React.PureComponent {
+export default class ClearColumnButton extends PureComponent {
 
   static propTypes = {
     onClick: PropTypes.func.isRequired,
diff --git a/app/javascript/mastodon/features/notifications/components/column_settings.js b/app/javascript/mastodon/features/notifications/components/column_settings.js
index 61df79b4646..5a05a479012 100644
--- a/app/javascript/mastodon/features/notifications/components/column_settings.js
+++ b/app/javascript/mastodon/features/notifications/components/column_settings.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import { FormattedMessage } from 'react-intl';
@@ -7,7 +7,7 @@ import GrantPermissionButton from './grant_permission_button';
 import SettingToggle from './setting_toggle';
 import { isStaff } from 'mastodon/initial_state';
 
-export default class ColumnSettings extends React.PureComponent {
+export default class ColumnSettings extends PureComponent {
 
   static propTypes = {
     settings: ImmutablePropTypes.map.isRequired,
diff --git a/app/javascript/mastodon/features/notifications/components/filter_bar.js b/app/javascript/mastodon/features/notifications/components/filter_bar.js
index 368eb0b7e6c..9e9b154cd9d 100644
--- a/app/javascript/mastodon/features/notifications/components/filter_bar.js
+++ b/app/javascript/mastodon/features/notifications/components/filter_bar.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 import Icon from 'mastodon/components/icon';
@@ -13,7 +13,7 @@ const tooltips = defineMessages({
 });
 
 export default @injectIntl
-class FilterBar extends React.PureComponent {
+class FilterBar extends PureComponent {
 
   static propTypes = {
     selectFilter: PropTypes.func.isRequired,
diff --git a/app/javascript/mastodon/features/notifications/components/follow_request.js b/app/javascript/mastodon/features/notifications/components/follow_request.js
index 9ef3fde7eb0..548871f4510 100644
--- a/app/javascript/mastodon/features/notifications/components/follow_request.js
+++ b/app/javascript/mastodon/features/notifications/components/follow_request.js
@@ -1,4 +1,3 @@
-import React, { Fragment } from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
 import Avatar from 'mastodon/components/avatar';
@@ -32,10 +31,10 @@ class FollowRequest extends ImmutablePureComponent {
 
     if (hidden) {
       return (
-        <Fragment>
+        <>
           {account.get('display_name')}
           {account.get('username')}
-        </Fragment>
+        </>
       );
     }
 
diff --git a/app/javascript/mastodon/features/notifications/components/grant_permission_button.js b/app/javascript/mastodon/features/notifications/components/grant_permission_button.js
index 798e4c7872b..06420c9a14c 100644
--- a/app/javascript/mastodon/features/notifications/components/grant_permission_button.js
+++ b/app/javascript/mastodon/features/notifications/components/grant_permission_button.js
@@ -1,8 +1,8 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import { FormattedMessage } from 'react-intl';
 
-export default class GrantPermissionButton extends React.PureComponent {
+export default class GrantPermissionButton extends PureComponent {
 
   static propTypes = {
     onClick: PropTypes.func.isRequired,
diff --git a/app/javascript/mastodon/features/notifications/components/notification.js b/app/javascript/mastodon/features/notifications/components/notification.js
index 0af71418c4c..8261cffbb88 100644
--- a/app/javascript/mastodon/features/notifications/components/notification.js
+++ b/app/javascript/mastodon/features/notifications/components/notification.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import { injectIntl, FormattedMessage, defineMessages } from 'react-intl';
 import { HotKeys } from 'react-hotkeys';
diff --git a/app/javascript/mastodon/features/notifications/components/notifications_permission_banner.js b/app/javascript/mastodon/features/notifications/components/notifications_permission_banner.js
index df9b7fb1b82..30a1e17f39d 100644
--- a/app/javascript/mastodon/features/notifications/components/notifications_permission_banner.js
+++ b/app/javascript/mastodon/features/notifications/components/notifications_permission_banner.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import Icon from 'mastodon/components/icon';
 import Button from 'mastodon/components/button';
 import IconButton from 'mastodon/components/icon_button';
@@ -14,7 +14,7 @@ const messages = defineMessages({
 
 export default @connect()
 @injectIntl
-class NotificationsPermissionBanner extends React.PureComponent {
+class NotificationsPermissionBanner extends PureComponent {
 
   static propTypes = {
     dispatch: PropTypes.func.isRequired,
diff --git a/app/javascript/mastodon/features/notifications/components/report.js b/app/javascript/mastodon/features/notifications/components/report.js
index 3ce3eb9d32f..75f87a4a456 100644
--- a/app/javascript/mastodon/features/notifications/components/report.js
+++ b/app/javascript/mastodon/features/notifications/components/report.js
@@ -1,4 +1,3 @@
-import React, { Fragment } from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
 import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
@@ -32,9 +31,9 @@ class Report extends ImmutablePureComponent {
 
     if (hidden) {
       return (
-        <Fragment>
+        <>
           {report.get('id')}
-        </Fragment>
+        </>
       );
     }
 
diff --git a/app/javascript/mastodon/features/notifications/components/setting_toggle.js b/app/javascript/mastodon/features/notifications/components/setting_toggle.js
index c4c8bffbe32..b054b36ff11 100644
--- a/app/javascript/mastodon/features/notifications/components/setting_toggle.js
+++ b/app/javascript/mastodon/features/notifications/components/setting_toggle.js
@@ -1,9 +1,9 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import Toggle from 'react-toggle';
 
-export default class SettingToggle extends React.PureComponent {
+export default class SettingToggle extends PureComponent {
 
   static propTypes = {
     prefix: PropTypes.string,
diff --git a/app/javascript/mastodon/features/notifications/index.js b/app/javascript/mastodon/features/notifications/index.js
index a6a277d7ed9..0f32431850f 100644
--- a/app/javascript/mastodon/features/notifications/index.js
+++ b/app/javascript/mastodon/features/notifications/index.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import { connect } from 'react-redux';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
@@ -67,7 +67,7 @@ const mapStateToProps = state => ({
 
 export default @connect(mapStateToProps)
 @injectIntl
-class Notifications extends React.PureComponent {
+class Notifications extends PureComponent {
 
   static propTypes = {
     columnId: PropTypes.string,
@@ -89,7 +89,7 @@ class Notifications extends React.PureComponent {
     trackScroll: true,
   };
 
-  componentWillMount() {
+  UNSAFE_componentWillMount() {
     this.props.dispatch(mountNotifications());
   }
 
diff --git a/app/javascript/mastodon/features/picture_in_picture/components/footer.js b/app/javascript/mastodon/features/picture_in_picture/components/footer.js
index 0cb42b25aac..74a0cf14932 100644
--- a/app/javascript/mastodon/features/picture_in_picture/components/footer.js
+++ b/app/javascript/mastodon/features/picture_in_picture/components/footer.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import { connect } from 'react-redux';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import ImmutablePropTypes from 'react-immutable-proptypes';
diff --git a/app/javascript/mastodon/features/picture_in_picture/components/header.js b/app/javascript/mastodon/features/picture_in_picture/components/header.js
index e05d8c62e90..58c35df6ec6 100644
--- a/app/javascript/mastodon/features/picture_in_picture/components/header.js
+++ b/app/javascript/mastodon/features/picture_in_picture/components/header.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import { connect } from 'react-redux';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import ImmutablePropTypes from 'react-immutable-proptypes';
diff --git a/app/javascript/mastodon/features/picture_in_picture/index.js b/app/javascript/mastodon/features/picture_in_picture/index.js
index 1e59fbcd337..76a764c3603 100644
--- a/app/javascript/mastodon/features/picture_in_picture/index.js
+++ b/app/javascript/mastodon/features/picture_in_picture/index.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { Component } from 'react';
 import { connect } from 'react-redux';
 import PropTypes from 'prop-types';
 import Video from 'mastodon/features/video';
@@ -12,7 +12,7 @@ const mapStateToProps = state => ({
 });
 
 export default @connect(mapStateToProps)
-class PictureInPicture extends React.Component {
+class PictureInPicture extends Component {
 
   static propTypes = {
     statusId: PropTypes.string,
diff --git a/app/javascript/mastodon/features/pinned_statuses/index.js b/app/javascript/mastodon/features/pinned_statuses/index.js
index 67b13f10aa7..11e90419b70 100644
--- a/app/javascript/mastodon/features/pinned_statuses/index.js
+++ b/app/javascript/mastodon/features/pinned_statuses/index.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import { connect } from 'react-redux';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
@@ -30,7 +29,7 @@ class PinnedStatuses extends ImmutablePureComponent {
     multiColumn: PropTypes.bool,
   };
 
-  componentWillMount () {
+  UNSAFE_componentWillMount () {
     this.props.dispatch(fetchPinnedStatuses());
   }
 
diff --git a/app/javascript/mastodon/features/public_timeline/components/column_settings.js b/app/javascript/mastodon/features/public_timeline/components/column_settings.js
index 756b6fe06da..78af8b5e37b 100644
--- a/app/javascript/mastodon/features/public_timeline/components/column_settings.js
+++ b/app/javascript/mastodon/features/public_timeline/components/column_settings.js
@@ -1,11 +1,11 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import { injectIntl, FormattedMessage } from 'react-intl';
 import SettingToggle from '../../notifications/components/setting_toggle';
 
 export default @injectIntl
-class ColumnSettings extends React.PureComponent {
+class ColumnSettings extends PureComponent {
 
   static propTypes = {
     settings: ImmutablePropTypes.map.isRequired,
diff --git a/app/javascript/mastodon/features/public_timeline/index.js b/app/javascript/mastodon/features/public_timeline/index.js
index b1d5518af55..8c7a8171364 100644
--- a/app/javascript/mastodon/features/public_timeline/index.js
+++ b/app/javascript/mastodon/features/public_timeline/index.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import { connect } from 'react-redux';
 import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 import PropTypes from 'prop-types';
@@ -31,7 +31,7 @@ const mapStateToProps = (state, { columnId }) => {
 
 export default @connect(mapStateToProps)
 @injectIntl
-class PublicTimeline extends React.PureComponent {
+class PublicTimeline extends PureComponent {
 
   static contextTypes = {
     router: PropTypes.object,
diff --git a/app/javascript/mastodon/features/reblogs/index.js b/app/javascript/mastodon/features/reblogs/index.js
index 7704a049f41..21c5a9854d9 100644
--- a/app/javascript/mastodon/features/reblogs/index.js
+++ b/app/javascript/mastodon/features/reblogs/index.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import { connect } from 'react-redux';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import PropTypes from 'prop-types';
@@ -32,13 +31,13 @@ class Reblogs extends ImmutablePureComponent {
     intl: PropTypes.object.isRequired,
   };
 
-  componentWillMount () {
+  UNSAFE_componentWillMount () {
     if (!this.props.accountIds) {
       this.props.dispatch(fetchReblogs(this.props.params.statusId));
     }
   }
 
-  componentWillReceiveProps(nextProps) {
+  UNSAFE_componentWillReceiveProps(nextProps) {
     if (nextProps.params.statusId !== this.props.params.statusId && nextProps.params.statusId) {
       this.props.dispatch(fetchReblogs(nextProps.params.statusId));
     }
diff --git a/app/javascript/mastodon/features/report/category.js b/app/javascript/mastodon/features/report/category.js
index 9215b3f51ed..a2592c9b5ec 100644
--- a/app/javascript/mastodon/features/report/category.js
+++ b/app/javascript/mastodon/features/report/category.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import { connect } from 'react-redux';
@@ -25,7 +25,7 @@ const mapStateToProps = state => ({
 
 export default @connect(mapStateToProps)
 @injectIntl
-class Category extends React.PureComponent {
+class Category extends PureComponent {
 
   static propTypes = {
     onNextStep: PropTypes.func.isRequired,
@@ -75,7 +75,7 @@ class Category extends React.PureComponent {
     ];
 
     return (
-      <React.Fragment>
+      <>
         <h3 className='report-dialog-modal__title'><FormattedMessage id='report.category.title' defaultMessage="Tell us what's going on with this {type}" values={{ type: intl.formatMessage(messages[startedFrom]) }} /></h3>
         <p className='report-dialog-modal__lead'><FormattedMessage id='report.category.subtitle' defaultMessage='Choose the best match' /></p>
 
@@ -98,7 +98,7 @@ class Category extends React.PureComponent {
         <div className='report-dialog-modal__actions'>
           <Button onClick={this.handleNextClick} disabled={category === null}><FormattedMessage id='report.next' defaultMessage='Next' /></Button>
         </div>
-      </React.Fragment>
+      </>
     );
   }
 
diff --git a/app/javascript/mastodon/features/report/comment.js b/app/javascript/mastodon/features/report/comment.js
index cde15641580..250a2b3d2ae 100644
--- a/app/javascript/mastodon/features/report/comment.js
+++ b/app/javascript/mastodon/features/report/comment.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import { injectIntl, defineMessages, FormattedMessage } from 'react-intl';
 import Button from 'mastodon/components/button';
@@ -9,7 +9,7 @@ const messages = defineMessages({
 });
 
 export default @injectIntl
-class Comment extends React.PureComponent {
+class Comment extends PureComponent {
 
   static propTypes = {
     onSubmit: PropTypes.func.isRequired,
@@ -48,7 +48,7 @@ class Comment extends React.PureComponent {
     const { comment, isRemote, forward, domain, isSubmitting, intl } = this.props;
 
     return (
-      <React.Fragment>
+      <>
         <h3 className='report-dialog-modal__title'><FormattedMessage id='report.comment.title' defaultMessage='Is there anything else you think we should know?' /></h3>
 
         <textarea
@@ -61,14 +61,14 @@ class Comment extends React.PureComponent {
         />
 
         {isRemote && (
-          <React.Fragment>
+          <>
             <p className='report-dialog-modal__lead'><FormattedMessage id='report.forward_hint' defaultMessage='The account is from another server. Send an anonymized copy of the report there as well?' /></p>
 
             <label className='report-dialog-modal__toggle'>
               <Toggle checked={forward} disabled={isSubmitting} onChange={this.handleForwardChange} />
               <FormattedMessage id='report.forward' defaultMessage='Forward to {target}' values={{ target: domain }} />
             </label>
-          </React.Fragment>
+          </>
         )}
 
         <div className='flex-spacer' />
@@ -76,7 +76,7 @@ class Comment extends React.PureComponent {
         <div className='report-dialog-modal__actions'>
           <Button onClick={this.handleClick} disabled={isSubmitting}><FormattedMessage id='report.submit' defaultMessage='Submit report' /></Button>
         </div>
-      </React.Fragment>
+      </>
     );
   }
 
diff --git a/app/javascript/mastodon/features/report/components/option.js b/app/javascript/mastodon/features/report/components/option.js
index 744d8526803..df6ef0e0f31 100644
--- a/app/javascript/mastodon/features/report/components/option.js
+++ b/app/javascript/mastodon/features/report/components/option.js
@@ -1,9 +1,9 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import classNames from 'classnames';
 import Check from 'mastodon/components/check';
 
-export default class Option extends React.PureComponent {
+export default class Option extends PureComponent {
 
   static propTypes = {
     name: PropTypes.string.isRequired,
diff --git a/app/javascript/mastodon/features/report/components/status_check_box.js b/app/javascript/mastodon/features/report/components/status_check_box.js
index 373c60e21e2..a8abcfaa253 100644
--- a/app/javascript/mastodon/features/report/components/status_check_box.js
+++ b/app/javascript/mastodon/features/report/components/status_check_box.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import StatusContent from 'mastodon/components/status_content';
@@ -8,7 +8,7 @@ import RelativeTimestamp from 'mastodon/components/relative_timestamp';
 import Option from './option';
 import MediaAttachments from 'mastodon/components/media_attachments';
 
-export default class StatusCheckBox extends React.PureComponent {
+export default class StatusCheckBox extends PureComponent {
 
   static propTypes = {
     id: PropTypes.string.isRequired,
diff --git a/app/javascript/mastodon/features/report/rules.js b/app/javascript/mastodon/features/report/rules.js
index f2db0d9e4cc..e804d195cb3 100644
--- a/app/javascript/mastodon/features/report/rules.js
+++ b/app/javascript/mastodon/features/report/rules.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import { connect } from 'react-redux';
@@ -11,7 +11,7 @@ const mapStateToProps = state => ({
 });
 
 export default @connect(mapStateToProps)
-class Rules extends React.PureComponent {
+class Rules extends PureComponent {
 
   static propTypes = {
     onNextStep: PropTypes.func.isRequired,
@@ -34,7 +34,7 @@ class Rules extends React.PureComponent {
     const { rules, selectedRuleIds } = this.props;
 
     return (
-      <React.Fragment>
+      <>
         <h3 className='report-dialog-modal__title'><FormattedMessage id='report.rules.title' defaultMessage='Which rules are being violated?' /></h3>
         <p className='report-dialog-modal__lead'><FormattedMessage id='report.rules.subtitle' defaultMessage='Select all that apply' /></p>
 
@@ -57,7 +57,7 @@ class Rules extends React.PureComponent {
         <div className='report-dialog-modal__actions'>
           <Button onClick={this.handleNextClick} disabled={selectedRuleIds.size < 1}><FormattedMessage id='report.next' defaultMessage='Next' /></Button>
         </div>
-      </React.Fragment>
+      </>
     );
   }
 
diff --git a/app/javascript/mastodon/features/report/statuses.js b/app/javascript/mastodon/features/report/statuses.js
index d5d86034fb5..3ced1111038 100644
--- a/app/javascript/mastodon/features/report/statuses.js
+++ b/app/javascript/mastodon/features/report/statuses.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import { connect } from 'react-redux';
@@ -14,7 +14,7 @@ const mapStateToProps = (state, { accountId }) => ({
 });
 
 export default @connect(mapStateToProps)
-class Statuses extends React.PureComponent {
+class Statuses extends PureComponent {
 
   static propTypes = {
     onNextStep: PropTypes.func.isRequired,
@@ -34,7 +34,7 @@ class Statuses extends React.PureComponent {
     const { availableStatusIds, selectedStatusIds, onToggle, isLoading } = this.props;
 
     return (
-      <React.Fragment>
+      <>
         <h3 className='report-dialog-modal__title'><FormattedMessage id='report.statuses.title' defaultMessage='Are there any posts that back up this report?' /></h3>
         <p className='report-dialog-modal__lead'><FormattedMessage id='report.statuses.subtitle' defaultMessage='Select all that apply' /></p>
 
@@ -54,7 +54,7 @@ class Statuses extends React.PureComponent {
         <div className='report-dialog-modal__actions'>
           <Button onClick={this.handleNextClick}><FormattedMessage id='report.next' defaultMessage='Next' /></Button>
         </div>
-      </React.Fragment>
+      </>
     );
   }
 
diff --git a/app/javascript/mastodon/features/report/thanks.js b/app/javascript/mastodon/features/report/thanks.js
index d169b1e3294..a58e948763d 100644
--- a/app/javascript/mastodon/features/report/thanks.js
+++ b/app/javascript/mastodon/features/report/thanks.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import { FormattedMessage } from 'react-intl';
@@ -13,7 +13,7 @@ import {
 const mapStateToProps = () => ({});
 
 export default @connect(mapStateToProps)
-class Thanks extends React.PureComponent {
+class Thanks extends PureComponent {
 
   static propTypes = {
     submitted: PropTypes.bool,
@@ -49,17 +49,17 @@ class Thanks extends React.PureComponent {
     const { account, submitted } = this.props;
 
     return (
-      <React.Fragment>
+      <>
         <h3 className='report-dialog-modal__title'>{submitted ? <FormattedMessage id='report.thanks.title_actionable' defaultMessage="Thanks for reporting, we'll look into this." /> : <FormattedMessage id='report.thanks.title' defaultMessage="Don't want to see this?" />}</h3>
         <p className='report-dialog-modal__lead'>{submitted ? <FormattedMessage id='report.thanks.take_action_actionable' defaultMessage='While we review this, you can take action against @{name}:' values={{ name: account.get('username') }} /> : <FormattedMessage id='report.thanks.take_action' defaultMessage='Here are your options for controlling what you see on Mastodon:' />}</p>
 
         {account.getIn(['relationship', 'following']) && (
-          <React.Fragment>
+          <>
             <h4 className='report-dialog-modal__subtitle'><FormattedMessage id='report.unfollow' defaultMessage='Unfollow @{name}' values={{ name: account.get('username') }} /></h4>
             <p className='report-dialog-modal__lead'><FormattedMessage id='report.unfollow_explanation' defaultMessage='You are following this account. To not see their posts in your home feed anymore, unfollow them.' /></p>
             <Button secondary onClick={this.handleUnfollowClick}><FormattedMessage id='account.unfollow' defaultMessage='Unfollow' /></Button>
             <hr />
-          </React.Fragment>
+          </>
         )}
 
         <h4 className='report-dialog-modal__subtitle'><FormattedMessage id='account.mute' defaultMessage='Mute @{name}' values={{ name: account.get('username') }} /></h4>
@@ -77,7 +77,7 @@ class Thanks extends React.PureComponent {
         <div className='report-dialog-modal__actions'>
           <Button onClick={this.handleCloseClick}><FormattedMessage id='report.close' defaultMessage='Done' /></Button>
         </div>
-      </React.Fragment>
+      </>
     );
   }
 
diff --git a/app/javascript/mastodon/features/standalone/compose/index.js b/app/javascript/mastodon/features/standalone/compose/index.js
index 0d764575fd7..610000036e3 100644
--- a/app/javascript/mastodon/features/standalone/compose/index.js
+++ b/app/javascript/mastodon/features/standalone/compose/index.js
@@ -1,10 +1,10 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import ComposeFormContainer from '../../compose/containers/compose_form_container';
 import NotificationsContainer from '../../ui/containers/notifications_container';
 import LoadingBarContainer from '../../ui/containers/loading_bar_container';
 import ModalContainer from '../../ui/containers/modal_container';
 
-export default class Compose extends React.PureComponent {
+export default class Compose extends PureComponent {
 
   render () {
     return (
diff --git a/app/javascript/mastodon/features/standalone/hashtag_timeline/index.js b/app/javascript/mastodon/features/standalone/hashtag_timeline/index.js
index d3d8a6507e6..f23c5c1f53d 100644
--- a/app/javascript/mastodon/features/standalone/hashtag_timeline/index.js
+++ b/app/javascript/mastodon/features/standalone/hashtag_timeline/index.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import { connect } from 'react-redux';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
@@ -16,7 +16,7 @@ const mapStateToProps = (state, { hashtag }) => ({
 });
 
 export default @connect(mapStateToProps)
-class HashtagTimeline extends React.PureComponent {
+class HashtagTimeline extends PureComponent {
 
   static propTypes = {
     dispatch: PropTypes.func.isRequired,
diff --git a/app/javascript/mastodon/features/standalone/public_timeline/index.js b/app/javascript/mastodon/features/standalone/public_timeline/index.js
index 19b0b14be6a..6a3530bde18 100644
--- a/app/javascript/mastodon/features/standalone/public_timeline/index.js
+++ b/app/javascript/mastodon/features/standalone/public_timeline/index.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import { connect } from 'react-redux';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
@@ -20,7 +20,7 @@ const mapStateToProps = (state, { local }) => {
 };
 
 export default @connect(mapStateToProps)
-class PublicTimeline extends React.PureComponent {
+class PublicTimeline extends PureComponent {
 
   static propTypes = {
     dispatch: PropTypes.func.isRequired,
diff --git a/app/javascript/mastodon/features/status/components/action_bar.js b/app/javascript/mastodon/features/status/components/action_bar.js
index edaff959e6c..2ece806f1af 100644
--- a/app/javascript/mastodon/features/status/components/action_bar.js
+++ b/app/javascript/mastodon/features/status/components/action_bar.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import { connect } from 'react-redux';
 import IconButton from '../../../components/icon_button';
@@ -46,7 +46,7 @@ const mapStateToProps = (state, { status }) => ({
 
 export default @connect(mapStateToProps)
 @injectIntl
-class ActionBar extends React.PureComponent {
+class ActionBar extends PureComponent {
 
   static contextTypes = {
     router: PropTypes.object,
diff --git a/app/javascript/mastodon/features/status/components/card.js b/app/javascript/mastodon/features/status/components/card.js
index 3d81bcb29b6..cad1526f300 100644
--- a/app/javascript/mastodon/features/status/components/card.js
+++ b/app/javascript/mastodon/features/status/components/card.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import Immutable from 'immutable';
 import ImmutablePropTypes from 'react-immutable-proptypes';
@@ -58,7 +58,7 @@ const addAutoPlay = html => {
   return html;
 };
 
-export default class Card extends React.PureComponent {
+export default class Card extends PureComponent {
 
   static propTypes = {
     card: ImmutablePropTypes.map,
@@ -82,7 +82,7 @@ export default class Card extends React.PureComponent {
     revealed: !this.props.sensitive,
   };
 
-  componentWillReceiveProps (nextProps) {
+  UNSAFE_componentWillReceiveProps (nextProps) {
     if (!Immutable.is(this.props.card, nextProps.card)) {
       this.setState({ embedded: false, previewLoaded: false });
     }
diff --git a/app/javascript/mastodon/features/status/components/detailed_status.js b/app/javascript/mastodon/features/status/components/detailed_status.js
index 13bce1b831f..6d7aaaea83e 100644
--- a/app/javascript/mastodon/features/status/components/detailed_status.js
+++ b/app/javascript/mastodon/features/status/components/detailed_status.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import Avatar from '../../../components/avatar';
@@ -178,7 +177,7 @@ class DetailedStatus extends ImmutablePureComponent {
     }
 
     if (status.get('application')) {
-      applicationLink = <React.Fragment> · <a className='detailed-status__application' href={status.getIn(['application', 'website'])} target='_blank' rel='noopener noreferrer'>{status.getIn(['application', 'name'])}</a></React.Fragment>;
+      applicationLink = <> · <a className='detailed-status__application' href={status.getIn(['application', 'website'])} target='_blank' rel='noopener noreferrer'>{status.getIn(['application', 'name'])}</a></>;
     }
 
     const visibilityIconInfo = {
@@ -189,33 +188,33 @@ class DetailedStatus extends ImmutablePureComponent {
     };
 
     const visibilityIcon = visibilityIconInfo[status.get('visibility')];
-    const visibilityLink = <React.Fragment> · <Icon id={visibilityIcon.icon} title={visibilityIcon.text} /></React.Fragment>;
+    const visibilityLink = <> · <Icon id={visibilityIcon.icon} title={visibilityIcon.text} /></>;
 
     if (['private', 'direct'].includes(status.get('visibility'))) {
       reblogLink = '';
     } else if (this.context.router) {
       reblogLink = (
-        <React.Fragment>
-          <React.Fragment> · </React.Fragment>
+        <>
+          <> · </>
           <Link to={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}/reblogs`} className='detailed-status__link'>
             <Icon id={reblogIcon} />
             <span className='detailed-status__reblogs'>
               <AnimatedNumber value={status.get('reblogs_count')} />
             </span>
           </Link>
-        </React.Fragment>
+        </>
       );
     } else {
       reblogLink = (
-        <React.Fragment>
-          <React.Fragment> · </React.Fragment>
+        <>
+          <> · </>
           <a href={`/interact/${status.get('id')}?type=reblog`} className='detailed-status__link' onClick={this.handleModalLink}>
             <Icon id={reblogIcon} />
             <span className='detailed-status__reblogs'>
               <AnimatedNumber value={status.get('reblogs_count')} />
             </span>
           </a>
-        </React.Fragment>
+        </>
       );
     }
 
@@ -241,10 +240,10 @@ class DetailedStatus extends ImmutablePureComponent {
 
     if (status.get('edited_at')) {
       edited = (
-        <React.Fragment>
-          <React.Fragment> · </React.Fragment>
+        <>
+          <> · </>
           <EditedTimestamp statusId={status.get('id')} timestamp={status.get('edited_at')} />
-        </React.Fragment>
+        </>
       );
     }
 
diff --git a/app/javascript/mastodon/features/status/index.js b/app/javascript/mastodon/features/status/index.js
index 4d7f24834e4..e54945368ce 100644
--- a/app/javascript/mastodon/features/status/index.js
+++ b/app/javascript/mastodon/features/status/index.js
@@ -1,5 +1,4 @@
 import Immutable from 'immutable';
-import React from 'react';
 import { connect } from 'react-redux';
 import PropTypes from 'prop-types';
 import classNames from 'classnames';
@@ -184,7 +183,7 @@ class Status extends ImmutablePureComponent {
     loadedStatusId: undefined,
   };
 
-  componentWillMount () {
+  UNSAFE_componentWillMount () {
     this.props.dispatch(fetchStatus(this.props.params.statusId));
   }
 
@@ -192,7 +191,7 @@ class Status extends ImmutablePureComponent {
     attachFullscreenListener(this.onFullScreenChange);
   }
 
-  componentWillReceiveProps (nextProps) {
+  UNSAFE_componentWillReceiveProps (nextProps) {
     if (nextProps.params.statusId !== this.props.params.statusId && nextProps.params.statusId) {
       this._scrolledIntoView = false;
       this.props.dispatch(fetchStatus(nextProps.params.statusId));
diff --git a/app/javascript/mastodon/features/ui/components/__tests__/column-test.js b/app/javascript/mastodon/features/ui/components/__tests__/column-test.js
index a56859be07b..8f935299fa2 100644
--- a/app/javascript/mastodon/features/ui/components/__tests__/column-test.js
+++ b/app/javascript/mastodon/features/ui/components/__tests__/column-test.js
@@ -1,5 +1,4 @@
 import { render, fireEvent, screen } from '@testing-library/react';
-import React from 'react';
 import Column from '../column';
 
 describe('<Column />', () => {
diff --git a/app/javascript/mastodon/features/ui/components/actions_modal.js b/app/javascript/mastodon/features/ui/components/actions_modal.js
index 875b2b75d7e..31318406fab 100644
--- a/app/javascript/mastodon/features/ui/components/actions_modal.js
+++ b/app/javascript/mastodon/features/ui/components/actions_modal.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import ImmutablePureComponent from 'react-immutable-pure-component';
diff --git a/app/javascript/mastodon/features/ui/components/audio_modal.js b/app/javascript/mastodon/features/ui/components/audio_modal.js
index c46fefce89d..fbf4c6151e9 100644
--- a/app/javascript/mastodon/features/ui/components/audio_modal.js
+++ b/app/javascript/mastodon/features/ui/components/audio_modal.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
 import Audio from 'mastodon/features/audio';
diff --git a/app/javascript/mastodon/features/ui/components/block_modal.js b/app/javascript/mastodon/features/ui/components/block_modal.js
index a07baeaa64a..3445cdbb3ca 100644
--- a/app/javascript/mastodon/features/ui/components/block_modal.js
+++ b/app/javascript/mastodon/features/ui/components/block_modal.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import { connect } from 'react-redux';
 import PropTypes from 'prop-types';
 import { injectIntl, FormattedMessage } from 'react-intl';
@@ -38,7 +38,7 @@ const mapDispatchToProps = dispatch => {
 
 export default @connect(makeMapStateToProps, mapDispatchToProps)
 @injectIntl
-class BlockModal extends React.PureComponent {
+class BlockModal extends PureComponent {
 
   static propTypes = {
     account: PropTypes.object.isRequired,
diff --git a/app/javascript/mastodon/features/ui/components/boost_modal.js b/app/javascript/mastodon/features/ui/components/boost_modal.js
index ab87ee42769..9c0c18ad42e 100644
--- a/app/javascript/mastodon/features/ui/components/boost_modal.js
+++ b/app/javascript/mastodon/features/ui/components/boost_modal.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import { connect } from 'react-redux';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
diff --git a/app/javascript/mastodon/features/ui/components/bundle.js b/app/javascript/mastodon/features/ui/components/bundle.js
index a60ace35ba6..7805f18dd54 100644
--- a/app/javascript/mastodon/features/ui/components/bundle.js
+++ b/app/javascript/mastodon/features/ui/components/bundle.js
@@ -1,10 +1,10 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 
 const emptyComponent = () => null;
 const noop = () => { };
 
-class Bundle extends React.PureComponent {
+class Bundle extends PureComponent {
 
   static propTypes = {
     fetchComponent: PropTypes.func.isRequired,
@@ -33,11 +33,11 @@ class Bundle extends React.PureComponent {
     forceRender: false,
   }
 
-  componentWillMount() {
+  UNSAFE_componentWillMount() {
     this.load(this.props);
   }
 
-  componentWillReceiveProps(nextProps) {
+  UNSAFE_componentWillReceiveProps(nextProps) {
     if (nextProps.fetchComponent !== this.props.fetchComponent) {
       this.load(nextProps);
     }
diff --git a/app/javascript/mastodon/features/ui/components/bundle_column_error.js b/app/javascript/mastodon/features/ui/components/bundle_column_error.js
index f39ebd900b1..38ad48a32b4 100644
--- a/app/javascript/mastodon/features/ui/components/bundle_column_error.js
+++ b/app/javascript/mastodon/features/ui/components/bundle_column_error.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import { defineMessages, injectIntl } from 'react-intl';
 
@@ -13,7 +13,7 @@ const messages = defineMessages({
   retry: { id: 'bundle_column_error.retry', defaultMessage: 'Try again' },
 });
 
-class BundleColumnError extends React.PureComponent {
+class BundleColumnError extends PureComponent {
 
   static propTypes = {
     onRetry: PropTypes.func.isRequired,
diff --git a/app/javascript/mastodon/features/ui/components/bundle_modal_error.js b/app/javascript/mastodon/features/ui/components/bundle_modal_error.js
index f9365b95bcc..d78008832cd 100644
--- a/app/javascript/mastodon/features/ui/components/bundle_modal_error.js
+++ b/app/javascript/mastodon/features/ui/components/bundle_modal_error.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import { defineMessages, injectIntl } from 'react-intl';
 
@@ -10,7 +10,7 @@ const messages = defineMessages({
   close: { id: 'bundle_modal_error.close', defaultMessage: 'Close' },
 });
 
-class BundleModalError extends React.PureComponent {
+class BundleModalError extends PureComponent {
 
   static propTypes = {
     onRetry: PropTypes.func.isRequired,
diff --git a/app/javascript/mastodon/features/ui/components/column.js b/app/javascript/mastodon/features/ui/components/column.js
index 15538ea387a..91ecf74523d 100644
--- a/app/javascript/mastodon/features/ui/components/column.js
+++ b/app/javascript/mastodon/features/ui/components/column.js
@@ -1,11 +1,11 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import ColumnHeader from './column_header';
 import PropTypes from 'prop-types';
 import { debounce } from 'lodash';
 import { scrollTop } from '../../../scroll';
 import { isMobile } from '../../../is_mobile';
 
-export default class Column extends React.PureComponent {
+export default class Column extends PureComponent {
 
   static propTypes = {
     heading: PropTypes.string,
diff --git a/app/javascript/mastodon/features/ui/components/column_header.js b/app/javascript/mastodon/features/ui/components/column_header.js
index b1a36e173d7..6360ceb9804 100644
--- a/app/javascript/mastodon/features/ui/components/column_header.js
+++ b/app/javascript/mastodon/features/ui/components/column_header.js
@@ -1,9 +1,9 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import classNames from 'classnames';
 import Icon from 'mastodon/components/icon';
 
-export default class ColumnHeader extends React.PureComponent {
+export default class ColumnHeader extends PureComponent {
 
   static propTypes = {
     icon: PropTypes.string,
diff --git a/app/javascript/mastodon/features/ui/components/column_link.js b/app/javascript/mastodon/features/ui/components/column_link.js
index 0a25f1ea203..5c6de4d858d 100644
--- a/app/javascript/mastodon/features/ui/components/column_link.js
+++ b/app/javascript/mastodon/features/ui/components/column_link.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import PropTypes from 'prop-types';
 import { Link } from 'react-router-dom';
 import Icon from 'mastodon/components/icon';
diff --git a/app/javascript/mastodon/features/ui/components/column_loading.js b/app/javascript/mastodon/features/ui/components/column_loading.js
index 0cdfd05d80e..87da4f42092 100644
--- a/app/javascript/mastodon/features/ui/components/column_loading.js
+++ b/app/javascript/mastodon/features/ui/components/column_loading.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import PropTypes from 'prop-types';
 
 import Column from '../../../components/column';
diff --git a/app/javascript/mastodon/features/ui/components/column_subheading.js b/app/javascript/mastodon/features/ui/components/column_subheading.js
index 8160c4aa394..e970a0bfdd0 100644
--- a/app/javascript/mastodon/features/ui/components/column_subheading.js
+++ b/app/javascript/mastodon/features/ui/components/column_subheading.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import PropTypes from 'prop-types';
 
 const ColumnSubheading = ({ text }) => {
diff --git a/app/javascript/mastodon/features/ui/components/columns_area.js b/app/javascript/mastodon/features/ui/components/columns_area.js
index 68017a5f1ef..0ae2e561542 100644
--- a/app/javascript/mastodon/features/ui/components/columns_area.js
+++ b/app/javascript/mastodon/features/ui/components/columns_area.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { Children, cloneElement } from 'react';
 import PropTypes from 'prop-types';
 import { defineMessages, injectIntl } from 'react-intl';
 import ImmutablePropTypes from 'react-immutable-proptypes';
@@ -78,7 +78,7 @@ class ColumnsArea extends ImmutablePureComponent {
     renderComposePanel: !(this.mediaQuery && this.mediaQuery.matches),
   }
 
-  componentWillReceiveProps() {
+  UNSAFE_componentWillReceiveProps() {
     if (typeof this.pendingIndex !== 'number' && this.lastIndex !== getIndex(this.context.router.history.location.pathname)) {
       this.setState({ shouldAnimate: false });
     }
@@ -104,7 +104,7 @@ class ColumnsArea extends ImmutablePureComponent {
     this.setState({ shouldAnimate: true });
   }
 
-  componentWillUpdate(nextProps) {
+  UNSAFE_componentWillUpdate(nextProps) {
     if (this.props.singleColumn !== nextProps.singleColumn && nextProps.singleColumn) {
       this.node.removeEventListener('wheel', this.handleWheel);
     }
@@ -191,7 +191,7 @@ class ColumnsArea extends ImmutablePureComponent {
     const icon = link.props['data-preview-icon'];
 
     const view = (index === columnIndex) ?
-      React.cloneElement(this.props.children) :
+      cloneElement(this.props.children) :
       <ColumnLoading title={title} icon={icon} />;
 
     return (
@@ -263,7 +263,7 @@ class ColumnsArea extends ImmutablePureComponent {
           );
         })}
 
-        {React.Children.map(children, child => React.cloneElement(child, { multiColumn: true }))}
+        {Children.map(children, child => cloneElement(child, { multiColumn: true }))}
       </div>
     );
   }
diff --git a/app/javascript/mastodon/features/ui/components/compare_history_modal.js b/app/javascript/mastodon/features/ui/components/compare_history_modal.js
index ecccc8f7df5..116347da240 100644
--- a/app/javascript/mastodon/features/ui/components/compare_history_modal.js
+++ b/app/javascript/mastodon/features/ui/components/compare_history_modal.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import { connect } from 'react-redux';
@@ -24,7 +24,7 @@ const mapDispatchToProps = dispatch => ({
 });
 
 export default @connect(mapStateToProps, mapDispatchToProps)
-class CompareHistoryModal extends React.PureComponent {
+class CompareHistoryModal extends PureComponent {
 
   static propTypes = {
     onClose: PropTypes.func.isRequired,
@@ -64,10 +64,10 @@ class CompareHistoryModal extends React.PureComponent {
         <div className='compare-history-modal__container'>
           <div className='status__content'>
             {currentVersion.get('spoiler_text').length > 0 && (
-              <React.Fragment>
+              <>
                 <div className='translate' dangerouslySetInnerHTML={spoilerContent} />
                 <hr />
-              </React.Fragment>
+              </>
             )}
 
             <div className='status__content__text status__content__text--visible translate' dangerouslySetInnerHTML={content} />
diff --git a/app/javascript/mastodon/features/ui/components/compose_panel.js b/app/javascript/mastodon/features/ui/components/compose_panel.js
index 3d0c48c7a96..ba0de17f1db 100644
--- a/app/javascript/mastodon/features/ui/components/compose_panel.js
+++ b/app/javascript/mastodon/features/ui/components/compose_panel.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import { connect } from 'react-redux';
 import PropTypes from 'prop-types';
 import SearchContainer from 'mastodon/features/compose/containers/search_container';
@@ -8,7 +8,7 @@ import LinkFooter from './link_footer';
 import { changeComposing } from 'mastodon/actions/compose';
 
 export default @connect()
-class ComposePanel extends React.PureComponent {
+class ComposePanel extends PureComponent {
 
   static propTypes = {
     dispatch: PropTypes.func.isRequired,
diff --git a/app/javascript/mastodon/features/ui/components/confirmation_modal.js b/app/javascript/mastodon/features/ui/components/confirmation_modal.js
index 65d97ca1610..648ef85d683 100644
--- a/app/javascript/mastodon/features/ui/components/confirmation_modal.js
+++ b/app/javascript/mastodon/features/ui/components/confirmation_modal.js
@@ -1,10 +1,10 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import { injectIntl, FormattedMessage } from 'react-intl';
 import Button from '../../../components/button';
 
 export default @injectIntl
-class ConfirmationModal extends React.PureComponent {
+class ConfirmationModal extends PureComponent {
 
   static propTypes = {
     message: PropTypes.node.isRequired,
diff --git a/app/javascript/mastodon/features/ui/components/drawer_loading.js b/app/javascript/mastodon/features/ui/components/drawer_loading.js
index 08b0d234767..11072ad98cc 100644
--- a/app/javascript/mastodon/features/ui/components/drawer_loading.js
+++ b/app/javascript/mastodon/features/ui/components/drawer_loading.js
@@ -1,5 +1,3 @@
-import React from 'react';
-
 const DrawerLoading = () => (
   <div className='drawer'>
     <div className='drawer__pager'>
diff --git a/app/javascript/mastodon/features/ui/components/embed_modal.js b/app/javascript/mastodon/features/ui/components/embed_modal.js
index 4679c9650fd..eb88dbe1f2e 100644
--- a/app/javascript/mastodon/features/ui/components/embed_modal.js
+++ b/app/javascript/mastodon/features/ui/components/embed_modal.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
diff --git a/app/javascript/mastodon/features/ui/components/focal_point_modal.js b/app/javascript/mastodon/features/ui/components/focal_point_modal.js
index a2e6b3d16b2..4655d000a00 100644
--- a/app/javascript/mastodon/features/ui/components/focal_point_modal.js
+++ b/app/javascript/mastodon/features/ui/components/focal_point_modal.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
 import ImmutablePureComponent from 'react-immutable-pure-component';
@@ -69,7 +69,7 @@ const removeExtraLineBreaks = str => str.replace(/\n\n/g, '******')
   .replace(/\n/g, ' ')
   .replace(/\*\*\*\*\*\*/g, '\n\n');
 
-class ImageLoader extends React.PureComponent {
+class ImageLoader extends PureComponent {
 
   static propTypes = {
     src: PropTypes.string.isRequired,
@@ -317,7 +317,7 @@ class FocalPointModal extends ImmutablePureComponent {
             {focals && <p><FormattedMessage id='upload_modal.hint' defaultMessage='Click or drag the circle on the preview to choose the focal point which will always be in view on all thumbnails.' /></p>}
 
             {thumbnailable && (
-              <React.Fragment>
+              <>
                 <label className='setting-text-label' htmlFor='upload-modal__thumbnail'><FormattedMessage id='upload_form.thumbnail' defaultMessage='Change thumbnail' /></label>
 
                 <Button disabled={isUploadingThumbnail} text={intl.formatMessage(messages.chooseImage)} onClick={this.handleFileInputClick} />
@@ -337,7 +337,7 @@ class FocalPointModal extends ImmutablePureComponent {
                 </label>
 
                 <hr className='setting-divider' />
-              </React.Fragment>
+              </>
             )}
 
             <label className='setting-text-label' htmlFor='upload-modal__description'>
diff --git a/app/javascript/mastodon/features/ui/components/follow_requests_nav_link.js b/app/javascript/mastodon/features/ui/components/follow_requests_nav_link.js
index 950ed7b273c..9d48a4cf12f 100644
--- a/app/javascript/mastodon/features/ui/components/follow_requests_nav_link.js
+++ b/app/javascript/mastodon/features/ui/components/follow_requests_nav_link.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { Component } from 'react';
 import PropTypes from 'prop-types';
 import { fetchFollowRequests } from 'mastodon/actions/accounts';
 import { connect } from 'react-redux';
@@ -13,7 +13,7 @@ const mapStateToProps = state => ({
 
 export default @withRouter
 @connect(mapStateToProps)
-class FollowRequestsNavLink extends React.Component {
+class FollowRequestsNavLink extends Component {
 
   static propTypes = {
     dispatch: PropTypes.func.isRequired,
diff --git a/app/javascript/mastodon/features/ui/components/image_loader.js b/app/javascript/mastodon/features/ui/components/image_loader.js
index c6f16a79237..2d3dc09a942 100644
--- a/app/javascript/mastodon/features/ui/components/image_loader.js
+++ b/app/javascript/mastodon/features/ui/components/image_loader.js
@@ -1,10 +1,10 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import classNames from 'classnames';
 import { LoadingBar } from 'react-redux-loading-bar';
 import ZoomableImage from './zoomable_image';
 
-export default class ImageLoader extends React.PureComponent {
+export default class ImageLoader extends PureComponent {
 
   static propTypes = {
     alt: PropTypes.string,
@@ -43,7 +43,7 @@ export default class ImageLoader extends React.PureComponent {
     this.loadImage(this.props);
   }
 
-  componentWillReceiveProps (nextProps) {
+  UNSAFE_componentWillReceiveProps (nextProps) {
     if (this.props.src !== nextProps.src) {
       this.loadImage(nextProps);
     }
diff --git a/app/javascript/mastodon/features/ui/components/link_footer.js b/app/javascript/mastodon/features/ui/components/link_footer.js
index edf1104c4ed..6196825d202 100644
--- a/app/javascript/mastodon/features/ui/components/link_footer.js
+++ b/app/javascript/mastodon/features/ui/components/link_footer.js
@@ -1,5 +1,5 @@
 import { connect } from 'react-redux';
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
 import { Link } from 'react-router-dom';
@@ -25,7 +25,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
 
 export default @injectIntl
 @connect(null, mapDispatchToProps)
-class LinkFooter extends React.PureComponent {
+class LinkFooter extends PureComponent {
 
   static propTypes = {
     withHotkeys: PropTypes.bool,
diff --git a/app/javascript/mastodon/features/ui/components/list_panel.js b/app/javascript/mastodon/features/ui/components/list_panel.js
index 411f62508ed..91962760342 100644
--- a/app/javascript/mastodon/features/ui/components/list_panel.js
+++ b/app/javascript/mastodon/features/ui/components/list_panel.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import ImmutablePureComponent from 'react-immutable-pure-component';
diff --git a/app/javascript/mastodon/features/ui/components/media_modal.js b/app/javascript/mastodon/features/ui/components/media_modal.js
index ae937d1cdf9..4d1ac43d7f7 100644
--- a/app/javascript/mastodon/features/ui/components/media_modal.js
+++ b/app/javascript/mastodon/features/ui/components/media_modal.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import ReactSwipeableViews from 'react-swipeable-views';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
diff --git a/app/javascript/mastodon/features/ui/components/modal_loading.js b/app/javascript/mastodon/features/ui/components/modal_loading.js
index f403ca4c9e9..7a6bbf5fa21 100644
--- a/app/javascript/mastodon/features/ui/components/modal_loading.js
+++ b/app/javascript/mastodon/features/ui/components/modal_loading.js
@@ -1,5 +1,3 @@
-import React from 'react';
-
 import LoadingIndicator from '../../../components/loading_indicator';
 
 // Keep the markup in sync with <BundleModalError />
diff --git a/app/javascript/mastodon/features/ui/components/modal_root.js b/app/javascript/mastodon/features/ui/components/modal_root.js
index 3fc235849df..020d5b2367b 100644
--- a/app/javascript/mastodon/features/ui/components/modal_root.js
+++ b/app/javascript/mastodon/features/ui/components/modal_root.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import { getScrollbarWidth } from 'mastodon/utils/scrollbar';
 import Base from 'mastodon/components/modal_root';
@@ -39,7 +39,7 @@ const MODAL_COMPONENTS = {
   'COMPARE_HISTORY': CompareHistoryModal,
 };
 
-export default class ModalRoot extends React.PureComponent {
+export default class ModalRoot extends PureComponent {
 
   static propTypes = {
     type: PropTypes.string,
diff --git a/app/javascript/mastodon/features/ui/components/mute_modal.js b/app/javascript/mastodon/features/ui/components/mute_modal.js
index d8d8e68c384..f7f1b875ab7 100644
--- a/app/javascript/mastodon/features/ui/components/mute_modal.js
+++ b/app/javascript/mastodon/features/ui/components/mute_modal.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import { connect } from 'react-redux';
 import PropTypes from 'prop-types';
 import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
@@ -45,7 +45,7 @@ const mapDispatchToProps = dispatch => {
 
 export default @connect(mapStateToProps, mapDispatchToProps)
 @injectIntl
-class MuteModal extends React.PureComponent {
+class MuteModal extends PureComponent {
 
   static propTypes = {
     account: PropTypes.object.isRequired,
diff --git a/app/javascript/mastodon/features/ui/components/navigation_panel.js b/app/javascript/mastodon/features/ui/components/navigation_panel.js
index fe4ed5d7721..c82eb142da2 100644
--- a/app/javascript/mastodon/features/ui/components/navigation_panel.js
+++ b/app/javascript/mastodon/features/ui/components/navigation_panel.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import { NavLink, withRouter } from 'react-router-dom';
 import { FormattedMessage } from 'react-intl';
 import Icon from 'mastodon/components/icon';
diff --git a/app/javascript/mastodon/features/ui/components/report_modal.js b/app/javascript/mastodon/features/ui/components/report_modal.js
index 744dd248b58..fdcc5706b8f 100644
--- a/app/javascript/mastodon/features/ui/components/report_modal.js
+++ b/app/javascript/mastodon/features/ui/components/report_modal.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import { connect } from 'react-redux';
 import { submitReport } from 'mastodon/actions/reports';
 import { expandAccountTimeline } from 'mastodon/actions/timelines';
diff --git a/app/javascript/mastodon/features/ui/components/tabs_bar.js b/app/javascript/mastodon/features/ui/components/tabs_bar.js
index 55668cab6a2..281dbd3ca22 100644
--- a/app/javascript/mastodon/features/ui/components/tabs_bar.js
+++ b/app/javascript/mastodon/features/ui/components/tabs_bar.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent, cloneElement } from 'react';
 import PropTypes from 'prop-types';
 import { NavLink, withRouter } from 'react-router-dom';
 import { FormattedMessage, injectIntl } from 'react-intl';
@@ -26,7 +26,7 @@ export function getLink (index) {
 
 export default @injectIntl
 @withRouter
-class TabsBar extends React.PureComponent {
+class TabsBar extends PureComponent {
 
   static propTypes = {
     intl: PropTypes.object.isRequired,
@@ -75,7 +75,7 @@ class TabsBar extends React.PureComponent {
     return (
       <div className='tabs-bar__wrapper'>
         <nav className='tabs-bar' ref={this.setRef}>
-          {links.map(link => React.cloneElement(link, { key: link.props.to, onClick: this.handleClick, 'aria-label': formatMessage({ id: link.props['data-preview-title-id'] }) }))}
+          {links.map(link => cloneElement(link, { key: link.props.to, onClick: this.handleClick, 'aria-label': formatMessage({ id: link.props['data-preview-title-id'] }) }))}
         </nav>
 
         <div id='tabs-bar__portal' />
diff --git a/app/javascript/mastodon/features/ui/components/upload_area.js b/app/javascript/mastodon/features/ui/components/upload_area.js
index 6c423b2c1d8..70bad0dc4c6 100644
--- a/app/javascript/mastodon/features/ui/components/upload_area.js
+++ b/app/javascript/mastodon/features/ui/components/upload_area.js
@@ -1,10 +1,10 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import Motion from '../../ui/util/optional_motion';
 import spring from 'react-motion/lib/spring';
 import { FormattedMessage } from 'react-intl';
 
-export default class UploadArea extends React.PureComponent {
+export default class UploadArea extends PureComponent {
 
   static propTypes = {
     active: PropTypes.bool,
diff --git a/app/javascript/mastodon/features/ui/components/video_modal.js b/app/javascript/mastodon/features/ui/components/video_modal.js
index f3ee89dfd91..a0c4cea3b83 100644
--- a/app/javascript/mastodon/features/ui/components/video_modal.js
+++ b/app/javascript/mastodon/features/ui/components/video_modal.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
 import Video from 'mastodon/features/video';
diff --git a/app/javascript/mastodon/features/ui/components/zoomable_image.js b/app/javascript/mastodon/features/ui/components/zoomable_image.js
index 1cf263cb900..1fc26964de8 100644
--- a/app/javascript/mastodon/features/ui/components/zoomable_image.js
+++ b/app/javascript/mastodon/features/ui/components/zoomable_image.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import IconButton from 'mastodon/components/icon_button';
 import { defineMessages, injectIntl } from 'react-intl';
@@ -92,7 +92,7 @@ const normalizeWheel = event => {
 };
 
 export default @injectIntl
-class ZoomableImage extends React.PureComponent {
+class ZoomableImage extends PureComponent {
 
   static propTypes = {
     alt: PropTypes.string,
@@ -410,7 +410,7 @@ class ZoomableImage extends React.PureComponent {
     const zoomButtonTitle = this.state.zoomState === 'compress' ? intl.formatMessage(messages.compress) : intl.formatMessage(messages.expand);
 
     return (
-      <React.Fragment>
+      <>
         <IconButton
           className={`media-modal__zoom-button ${zoomButtonShouldHide}`}
           title={zoomButtonTitle}
@@ -443,7 +443,7 @@ class ZoomableImage extends React.PureComponent {
             onMouseDown={this.handleMouseDown}
           />
         </div>
-      </React.Fragment>
+      </>
     );
   }
 
diff --git a/app/javascript/mastodon/features/ui/index.js b/app/javascript/mastodon/features/ui/index.js
index 9a901f12a65..425e82f8e89 100644
--- a/app/javascript/mastodon/features/ui/index.js
+++ b/app/javascript/mastodon/features/ui/index.js
@@ -1,5 +1,5 @@
 import classNames from 'classnames';
-import React from 'react';
+import { PureComponent } from 'react';
 import { HotKeys } from 'react-hotkeys';
 import { defineMessages, injectIntl } from 'react-intl';
 import { connect } from 'react-redux';
@@ -108,7 +108,7 @@ const keyMap = {
   openMedia: 'e',
 };
 
-class SwitchingColumnsArea extends React.PureComponent {
+class SwitchingColumnsArea extends PureComponent {
 
   static propTypes = {
     children: PropTypes.node,
@@ -116,7 +116,7 @@ class SwitchingColumnsArea extends React.PureComponent {
     mobile: PropTypes.bool,
   };
 
-  componentWillMount () {
+  UNSAFE_componentWillMount () {
     if (this.props.mobile) {
       document.body.classList.toggle('layout-single-column', true);
       document.body.classList.toggle('layout-multiple-columns', false);
@@ -204,7 +204,7 @@ class SwitchingColumnsArea extends React.PureComponent {
 export default @connect(mapStateToProps)
 @injectIntl
 @withRouter
-class UI extends React.PureComponent {
+class UI extends PureComponent {
 
   static contextTypes = {
     router: PropTypes.object.isRequired,
diff --git a/app/javascript/mastodon/features/ui/util/react_router_helpers.js b/app/javascript/mastodon/features/ui/util/react_router_helpers.js
index d452b871f78..74b6ea7f99f 100644
--- a/app/javascript/mastodon/features/ui/util/react_router_helpers.js
+++ b/app/javascript/mastodon/features/ui/util/react_router_helpers.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { Children, Component, PureComponent, cloneElement } from 'react';
 import PropTypes from 'prop-types';
 import { Switch, Route } from 'react-router-dom';
 
@@ -7,14 +7,14 @@ import BundleColumnError from '../components/bundle_column_error';
 import BundleContainer from '../containers/bundle_container';
 
 // Small wrapper to pass multiColumn to the route components
-export class WrappedSwitch extends React.PureComponent {
+export class WrappedSwitch extends PureComponent {
 
   render () {
     const { multiColumn, children } = this.props;
 
     return (
       <Switch>
-        {React.Children.map(children, child => React.cloneElement(child, { multiColumn }))}
+        {Children.map(children, child => cloneElement(child, { multiColumn }))}
       </Switch>
     );
   }
@@ -29,7 +29,7 @@ WrappedSwitch.propTypes = {
 // Small Wrapper to extract the params from the route and pass
 // them to the rendered component, together with the content to
 // be rendered inside (the children)
-export class WrappedRoute extends React.Component {
+export class WrappedRoute extends Component {
 
   static propTypes = {
     component: PropTypes.func.isRequired,
diff --git a/app/javascript/mastodon/features/ui/util/reduced_motion.js b/app/javascript/mastodon/features/ui/util/reduced_motion.js
index 95519042b43..b33742e0f2b 100644
--- a/app/javascript/mastodon/features/ui/util/reduced_motion.js
+++ b/app/javascript/mastodon/features/ui/util/reduced_motion.js
@@ -1,6 +1,6 @@
 // Like react-motion's Motion, but reduces all animations to cross-fades
 // for the benefit of users with motion sickness.
-import React from 'react';
+import { Component } from 'react';
 import Motion from 'react-motion/lib/Motion';
 import PropTypes from 'prop-types';
 
@@ -11,7 +11,7 @@ const extractValue = (value) => {
   return (typeof value === 'object' && value && 'val' in value) ? value.val : value;
 };
 
-class ReducedMotion extends React.Component {
+class ReducedMotion extends Component {
 
   static propTypes = {
     defaultStyle: PropTypes.object,
diff --git a/app/javascript/mastodon/features/video/index.js b/app/javascript/mastodon/features/video/index.js
index 4f90e955fe7..d5cd94a6b22 100644
--- a/app/javascript/mastodon/features/video/index.js
+++ b/app/javascript/mastodon/features/video/index.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 import { is } from 'immutable';
@@ -95,7 +95,7 @@ export const fileNameFromURL = str => {
 };
 
 export default @injectIntl
-class Video extends React.PureComponent {
+class Video extends PureComponent {
 
   static propTypes = {
     preview: PropTypes.string,
@@ -391,7 +391,7 @@ class Video extends React.PureComponent {
     }
   }
 
-  componentWillReceiveProps (nextProps) {
+  UNSAFE_componentWillReceiveProps (nextProps) {
     if (!is(nextProps.visible, this.props.visible) && nextProps.visible !== undefined) {
       this.setState({ revealed: nextProps.visible });
     }
diff --git a/app/javascript/mastodon/main.js b/app/javascript/mastodon/main.js
index bda51f692b7..2795f3e2022 100644
--- a/app/javascript/mastodon/main.js
+++ b/app/javascript/mastodon/main.js
@@ -1,11 +1,10 @@
-import * as registerPushNotifications from './actions/push_notifications';
-import { setupBrowserNotifications } from './actions/notifications';
-import { default as Mastodon, store } from './containers/mastodon';
-import React from 'react';
-import ReactDOM from 'react-dom';
-import ready from './ready';
+import { createRoot } from 'react-dom/client';
+import * as registerPushNotifications from 'mastodon/actions/push_notifications';
+import { setupBrowserNotifications } from 'mastodon/actions/notifications';
+import { default as Mastodon, store } from 'mastodon/containers/mastodon';
+import ready from 'mastodon/ready';
 
-const perf = require('./performance');
+const perf = require('mastodon/performance');
 
 function main() {
   perf.start('main()');
@@ -20,9 +19,10 @@ function main() {
 
   ready(() => {
     const mountNode = document.getElementById('mastodon');
-    const props = JSON.parse(mountNode.getAttribute('data-props'));
+    const root      = createRoot(mountNode);
+    const props     = JSON.parse(mountNode.getAttribute('data-props'));
 
-    ReactDOM.render(<Mastodon {...props} />, mountNode);
+    root.render(<Mastodon {...props} />);
     store.dispatch(setupBrowserNotifications());
     if (process.env.NODE_ENV === 'production') {
       // avoid offline in dev mode because it's harder to debug
diff --git a/app/javascript/packs/about.js b/app/javascript/packs/about.js
index 892d825ece2..7c25f99db16 100644
--- a/app/javascript/packs/about.js
+++ b/app/javascript/packs/about.js
@@ -1,23 +1,26 @@
 import './public-path';
-import loadPolyfills from '../mastodon/load_polyfills';
-import { start } from '../mastodon/common';
+
+import loadPolyfills from 'mastodon/load_polyfills';
+import { start } from 'mastodon/common';
 
 start();
 
 function loaded() {
-  const TimelineContainer = require('../mastodon/containers/timeline_container').default;
-  const React             = require('react');
-  const ReactDOM          = require('react-dom');
-  const mountNode         = document.getElementById('mastodon-timeline');
+  const { createRoot }                 = require('react-dom/client');
+  const { default: TimelineContainer } = require('mastodon/containers/timeline_container');
+
+  const mountNode = document.getElementById('mastodon-timeline');
 
   if (mountNode !== null) {
+    const root  = createRoot(mountNode);
     const props = JSON.parse(mountNode.getAttribute('data-props'));
-    ReactDOM.render(<TimelineContainer {...props} />, mountNode);
+
+    root.render(<TimelineContainer {...props} />);
   }
 }
 
 function main() {
-  const ready = require('../mastodon/ready').default;
+  const { default: ready } = require('mastodon/ready');
   ready(loaded);
 }
 
diff --git a/app/javascript/packs/admin.js b/app/javascript/packs/admin.js
index a3ed1ffedd8..2f6807318a7 100644
--- a/app/javascript/packs/admin.js
+++ b/app/javascript/packs/admin.js
@@ -1,6 +1,7 @@
 import './public-path';
+
 import { delegate } from '@rails/ujs';
-import ready from '../mastodon/ready';
+import ready from 'mastodon/ready';
 
 const batchCheckboxClassName = '.batch-checkbox input[type="checkbox"]';
 
@@ -110,21 +111,23 @@ ready(() => {
     }
   });
 
-  const React    = require('react');
-  const ReactDOM = require('react-dom');
+  const { createRoot } = require('react-dom/client');
 
   [].forEach.call(document.querySelectorAll('[data-admin-component]'), element => {
     const componentName  = element.getAttribute('data-admin-component');
     const { locale, ...componentProps } = JSON.parse(element.getAttribute('data-props'));
 
-    import('../mastodon/containers/admin_component').then(({ default: AdminComponent }) => {
-      return import('../mastodon/components/admin/' + componentName).then(({ default: Component }) => {
-        ReactDOM.render((
-          <AdminComponent locale={locale}>
-            <Component {...componentProps} />
-          </AdminComponent>
-        ), element);
-      });
+    Promise.all([
+      import('mastodon/containers/admin_component'),
+      import('mastodon/components/admin/' + componentName),
+    ]).then(({ default: AdminComponent }, { default: Component }) => {
+      const root = createRoot(element);
+
+      root.render((
+        <AdminComponent locale={locale}>
+          <Component {...componentProps} />
+        </AdminComponent>
+      ));
     }).catch(error => {
       console.error(error);
     });
diff --git a/app/javascript/packs/public.js b/app/javascript/packs/public.js
index e42468e0c69..f3a3f8c071a 100644
--- a/app/javascript/packs/public.js
+++ b/app/javascript/packs/public.js
@@ -1,9 +1,10 @@
 import './public-path';
+
 import escapeTextContentForBrowser from 'escape-html';
-import loadPolyfills from '../mastodon/load_polyfills';
-import ready from '../mastodon/ready';
-import { start } from '../mastodon/common';
-import loadKeyboardExtensions from '../mastodon/load_keyboard_extensions';
+import loadPolyfills from 'mastodon/load_polyfills';
+import ready from 'mastodon/ready';
+import { start } from 'mastodon/common';
+import loadKeyboardExtensions from 'mastodon/load_keyboard_extensions';
 import 'cocoon-js-vanilla';
 
 start();
@@ -25,16 +26,16 @@ window.addEventListener('message', e => {
 });
 
 function main() {
-  const IntlMessageFormat = require('intl-messageformat').default;
-  const { timeAgoString } = require('../mastodon/components/relative_timestamp');
-  const { delegate } = require('@rails/ujs');
-  const emojify = require('../mastodon/features/emoji/emoji').default;
-  const { getLocale } = require('../mastodon/locales');
+  const { delegate }                   = require('@rails/ujs');
+  const { createBrowserHistory }       = require('history');
+  const { default: IntlMessageFormat } = require('intl-messageformat');
+  const { createRoot }                 = require('react-dom/client');
+  const Rellax                         = require('rellax');
+  const { timeAgoString }              = require('mastodon/components/relative_timestamp');
+  const { default: emojify }           = require('mastodon/features/emoji/emoji');
+  const { getLocale }                  = require('mastodon/locales');
+
   const { messages } = getLocale();
-  const React = require('react');
-  const ReactDOM = require('react-dom');
-  const Rellax = require('rellax');
-  const { createBrowserHistory } = require('history');
 
   const scrollToDetailedStatus = () => {
     const history = createBrowserHistory();
@@ -99,8 +100,9 @@ function main() {
           });
 
           const content = document.createElement('div');
+          const root    = createRoot(content);
 
-          ReactDOM.render(<MediaContainer locale={locale} components={reactComponents} />, content);
+          root.render(<MediaContainer locale={locale} components={reactComponents} />);
           document.body.appendChild(content);
           scrollToDetailedStatus();
         })
diff --git a/app/javascript/packs/share.js b/app/javascript/packs/share.js
index 1225d7b5294..c10e854ab88 100644
--- a/app/javascript/packs/share.js
+++ b/app/javascript/packs/share.js
@@ -1,23 +1,27 @@
 import './public-path';
-import loadPolyfills from '../mastodon/load_polyfills';
-import { start } from '../mastodon/common';
+
+import loadPolyfills from 'mastodon/load_polyfills';
+import { start } from 'mastodon/common';
 
 start();
 
 function loaded() {
-  const ComposeContainer = require('../mastodon/containers/compose_container').default;
-  const React = require('react');
-  const ReactDOM = require('react-dom');
+  const { createRoot }                = require('react-dom/client');
+  const { default: ComposeContainer } = require('mastodon/containers/compose_container');
+
   const mountNode = document.getElementById('mastodon-compose');
 
   if (mountNode !== null) {
+    const root  = createRoot(mountNode);
     const props = JSON.parse(mountNode.getAttribute('data-props'));
-    ReactDOM.render(<ComposeContainer {...props} />, mountNode);
+
+    root.render(<ComposeContainer {...props} />);
   }
 }
 
 function main() {
-  const ready = require('../mastodon/ready').default;
+  const { default: ready }= require('mastodon/ready');
+
   ready(loaded);
 }
 
diff --git a/babel.config.js b/babel.config.js
index b040cc15960..404d8614e75 100644
--- a/babel.config.js
+++ b/babel.config.js
@@ -3,6 +3,7 @@ module.exports = (api) => {
 
   const reactOptions = {
     development: false,
+    runtime: 'automatic',
   };
 
   const envOptions = {
diff --git a/package.json b/package.json
index c263538e969..b42e3b9ff63 100644
--- a/package.json
+++ b/package.json
@@ -91,8 +91,8 @@
     "promise.prototype.finally": "^3.1.3",
     "prop-types": "^15.8.1",
     "punycode": "^2.1.0",
-    "react": "^16.14.0",
-    "react-dom": "^16.14.0",
+    "react": "^18.1.0",
+    "react-dom": "^18.1.0",
     "react-hotkeys": "^1.1.4",
     "react-immutable-proptypes": "^2.2.0",
     "react-immutable-pure-component": "^2.2.2",
@@ -101,7 +101,7 @@
     "react-motion": "^0.5.2",
     "react-notification": "^6.8.5",
     "react-overlays": "^0.9.3",
-    "react-redux": "^7.2.8",
+    "react-redux": "^8.0.1",
     "react-redux-loading-bar": "^4.0.8",
     "react-router-dom": "^4.1.1",
     "react-router-scroll-4": "^1.0.0-beta.1",
@@ -141,7 +141,7 @@
   "devDependencies": {
     "@babel/eslint-parser": "^7.18.2",
     "@testing-library/jest-dom": "^5.16.4",
-    "@testing-library/react": "^12.1.5",
+    "@testing-library/react": "^13.2.0",
     "babel-jest": "^28.1.1",
     "eslint": "^7.32.0",
     "eslint-plugin-import": "~2.26.0",
@@ -154,7 +154,7 @@
     "prettier": "^2.7.1",
     "raf": "^3.4.1",
     "react-intl-translations-manager": "^5.0.3",
-    "react-test-renderer": "^16.14.0",
+    "react-test-renderer": "^18.1.0",
     "stylelint": "^14.9.1",
     "stylelint-config-standard-scss": "^4.0.0",
     "webpack-dev-server": "^3.11.3",
diff --git a/yarn.lock b/yarn.lock
index 12b02d95c9e..72765fffe68 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1028,7 +1028,14 @@
   dependencies:
     regenerator-runtime "^0.12.0"
 
-"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.18.6", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
+"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.16.3", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
+  version "7.17.9"
+  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.9.tgz#d19fbf802d01a8cb6cf053a64e472d42c434ba72"
+  integrity sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==
+  dependencies:
+    regenerator-runtime "^0.13.4"
+
+"@babel/runtime@^7.18.6":
   version "7.18.6"
   resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.6.tgz#6a1ef59f838debd670421f8c7f2cbb8da9751580"
   integrity sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ==
@@ -1587,17 +1594,17 @@
   dependencies:
     "@sinonjs/commons" "^1.7.0"
 
-"@testing-library/dom@^8.0.0":
-  version "8.1.0"
-  resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.1.0.tgz#f8358b1883844ea569ba76b7e94582168df5370d"
-  integrity sha512-kmW9alndr19qd6DABzQ978zKQ+J65gU2Rzkl8hriIetPnwpesRaK4//jEQyYh8fEALmGhomD/LBQqt+o+DL95Q==
+"@testing-library/dom@^8.5.0":
+  version "8.13.0"
+  resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.13.0.tgz#bc00bdd64c7d8b40841e27a70211399ad3af46f5"
+  integrity sha512-9VHgfIatKNXQNaZTtLnalIy0jNZzY35a4S3oi08YAt9Hv1VsfZ/DfA45lM8D/UhtHBGJ4/lGwp0PZkVndRkoOQ==
   dependencies:
     "@babel/code-frame" "^7.10.4"
     "@babel/runtime" "^7.12.5"
     "@types/aria-query" "^4.2.0"
-    aria-query "^4.2.2"
+    aria-query "^5.0.0"
     chalk "^4.1.0"
-    dom-accessibility-api "^0.5.6"
+    dom-accessibility-api "^0.5.9"
     lz-string "^1.4.4"
     pretty-format "^27.0.2"
 
@@ -1616,14 +1623,14 @@
     lodash "^4.17.15"
     redent "^3.0.0"
 
-"@testing-library/react@^12.1.5":
-  version "12.1.5"
-  resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-12.1.5.tgz#bb248f72f02a5ac9d949dea07279095fa577963b"
-  integrity sha512-OfTXCJUFgjd/digLUuPxa0+/3ZxsQmE7ub9kcbW/wi96Bh3o/p5vrETcBGfP17NWPGqeYYl5LTRpwyGoMC4ysg==
+"@testing-library/react@^13.2.0":
+  version "13.2.0"
+  resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-13.2.0.tgz#2db00bc94d71c4e90e5c25582e90a650ae2925bf"
+  integrity sha512-Bprbz/SZVONCJy5f7hcihNCv313IJXdYiv0nSJklIs1SQCIHHNlnGNkosSXnGZTmesyGIcBGNppYhXcc11pb7g==
   dependencies:
     "@babel/runtime" "^7.12.5"
-    "@testing-library/dom" "^8.0.0"
-    "@types/react-dom" "<18.0.0"
+    "@testing-library/dom" "^8.5.0"
+    "@types/react-dom" "^18.0.0"
 
 "@tootallnate/once@2":
   version "2.0.0"
@@ -1694,7 +1701,7 @@
   dependencies:
     "@types/node" "*"
 
-"@types/hoist-non-react-statics@^3.3.0":
+"@types/hoist-non-react-statics@^3.3.1":
   version "3.3.1"
   resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f"
   integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==
@@ -1801,22 +1808,12 @@
   resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8"
   integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==
 
-"@types/react-dom@<18.0.0":
-  version "17.0.15"
-  resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.15.tgz#f2c8efde11521a4b7991e076cb9c70ba3bb0d156"
-  integrity sha512-Tr9VU9DvNoHDWlmecmcsE5ZZiUkYx+nKBzum4Oxe1K0yJVyBlfbq7H3eXjxXqJczBKqPGq3EgfTru4MgKb9+Yw==
-  dependencies:
-    "@types/react" "^17"
-
-"@types/react-redux@^7.1.20":
-  version "7.1.20"
-  resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.20.tgz#42f0e61ababb621e12c66c96dda94c58423bd7df"
-  integrity sha512-q42es4c8iIeTgcnB+yJgRTTzftv3eYYvCZOh1Ckn2eX/3o5TdsQYKUWpLoLuGlcY/p+VAhV9IOEZJcWk/vfkXw==
+"@types/react-dom@^18.0.0":
+  version "18.0.3"
+  resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.0.3.tgz#a022ea08c75a476fe5e96b675c3e673363853831"
+  integrity sha512-1RRW9kst+67gveJRYPxGmVy8eVJ05O43hg77G2j5m76/RFJtMbcfAs2viQ2UNsvvDg8F7OfQZx8qQcl6ymygaQ==
   dependencies:
-    "@types/hoist-non-react-statics" "^3.3.0"
     "@types/react" "*"
-    hoist-non-react-statics "^3.3.0"
-    redux "^4.0.0"
 
 "@types/react-transition-group@^4.4.0":
   version "4.4.3"
@@ -1834,15 +1831,6 @@
     "@types/scheduler" "*"
     csstype "^3.0.2"
 
-"@types/react@^17":
-  version "17.0.44"
-  resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.44.tgz#c3714bd34dd551ab20b8015d9d0dbec812a51ec7"
-  integrity sha512-Ye0nlw09GeMp2Suh8qoOv0odfgCoowfM/9MG6WeRD60Gq9wS90bdkdRtYbRkNhXOpG4H+YXGvj4wOWhAC0LJ1g==
-  dependencies:
-    "@types/prop-types" "*"
-    "@types/scheduler" "*"
-    csstype "^3.0.2"
-
 "@types/scheduler@*":
   version "0.16.1"
   resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.1.tgz#18845205e86ff0038517aab7a18a62a6b9f71275"
@@ -1870,6 +1858,11 @@
   resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.2.tgz#6286b4c7228d58ab7866d19716f3696e03a09397"
   integrity sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==
 
+"@types/use-sync-external-store@^0.0.3":
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz#b6725d5f4af24ace33b36fafd295136e75509f43"
+  integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==
+
 "@types/yargs-parser@*":
   version "15.0.0"
   resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d"
@@ -4117,6 +4110,11 @@ dom-accessibility-api@^0.5.6:
   resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.6.tgz#3f5d43b52c7a3bd68b5fb63fa47b4e4c1fdf65a9"
   integrity sha512-DplGLZd8L1lN64jlT27N9TVSESFR5STaEJvX+thCby7fuCHonfPpAlodYc3vuUYbDuDec5w8AMP7oCM5TWFsqw==
 
+dom-accessibility-api@^0.5.9:
+  version "0.5.14"
+  resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.14.tgz#56082f71b1dc7aac69d83c4285eef39c15d93f56"
+  integrity sha512-NMt+m9zFMPZe0JcY9gN224Qvk6qLIdqex29clBvc/y75ZBX9YA9wNK3frsYvu2DI1xcCIwxwnX+TlsJ2DSOADg==
+
 dom-helpers@^3.2.1, dom-helpers@^3.4.0:
   version "3.4.0"
   resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.4.0.tgz#e9b369700f959f62ecde5a6babde4bccd9169af8"
@@ -8877,7 +8875,7 @@ prop-types-extra@^1.0.1:
     react-is "^16.3.2"
     warning "^4.0.0"
 
-prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1:
+prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.8.1:
   version "15.8.1"
   resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
   integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@@ -9035,15 +9033,13 @@ raw-body@2.5.1:
     iconv-lite "0.4.24"
     unpipe "1.0.0"
 
-react-dom@^16.14.0:
-  version "16.14.0"
-  resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.14.0.tgz#7ad838ec29a777fb3c75c3a190f661cf92ab8b89"
-  integrity sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==
+react-dom@^18.1.0:
+  version "18.1.0"
+  resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.1.0.tgz#7f6dd84b706408adde05e1df575b3a024d7e8a2f"
+  integrity sha512-fU1Txz7Budmvamp7bshe4Zi32d0ll7ect+ccxNu9FlObT605GOEB8BfO4tmRJ39R5Zj831VCpvQ05QPBW5yb+w==
   dependencies:
     loose-envify "^1.1.0"
-    object-assign "^4.1.1"
-    prop-types "^15.6.2"
-    scheduler "^0.19.1"
+    scheduler "^0.22.0"
 
 react-event-listener@^0.6.0:
   version "0.6.6"
@@ -9105,21 +9101,21 @@ react-intl@^2.9.0:
     intl-relativeformat "^2.1.0"
     invariant "^2.1.1"
 
-react-is@^16.12.0, react-is@^16.13.1, react-is@^16.3.2, react-is@^16.7.0, react-is@^16.8.6:
+react-is@^16.12.0, react-is@^16.13.1, react-is@^16.3.2, react-is@^16.7.0:
   version "16.13.1"
   resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
   integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
 
-react-is@^17.0.1, react-is@^17.0.2:
-  version "17.0.2"
-  resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
-  integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
-
-react-is@^18.0.0:
+"react-is@^16.12.0 || ^17.0.0 || ^18.0.0", react-is@^18.0.0, react-is@^18.1.0:
   version "18.1.0"
   resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.1.0.tgz#61aaed3096d30eacf2a2127118b5b41387d32a67"
   integrity sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==
 
+react-is@^17.0.1:
+  version "17.0.2"
+  resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
+  integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
+
 react-lifecycles-compat@^3.0.2, react-lifecycles-compat@^3.0.4:
   version "3.0.4"
   resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
@@ -9170,17 +9166,17 @@ react-redux-loading-bar@^4.0.8:
     prop-types "^15.6.2"
     react-lifecycles-compat "^3.0.2"
 
-react-redux@^7.2.8:
-  version "7.2.8"
-  resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.8.tgz#a894068315e65de5b1b68899f9c6ee0923dd28de"
-  integrity sha512-6+uDjhs3PSIclqoCk0kd6iX74gzrGc3W5zcAjbrFgEdIjRSQObdIwfx80unTkVUYvbQ95Y8Av3OvFHq1w5EOUw==
+react-redux@^8.0.1:
+  version "8.0.1"
+  resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.0.1.tgz#2bc029f5ada9b443107914c373a2750f6bc0f40c"
+  integrity sha512-LMZMsPY4DYdZfLJgd7i79n5Kps5N9XVLCJJeWAaPYTV+Eah2zTuBjTxKtNEbjiyitbq80/eIkm55CYSLqAub3w==
   dependencies:
-    "@babel/runtime" "^7.15.4"
-    "@types/react-redux" "^7.1.20"
+    "@babel/runtime" "^7.12.1"
+    "@types/hoist-non-react-statics" "^3.3.1"
+    "@types/use-sync-external-store" "^0.0.3"
     hoist-non-react-statics "^3.3.2"
-    loose-envify "^1.4.0"
-    prop-types "^15.7.2"
-    react-is "^17.0.2"
+    react-is "^18.0.0"
+    use-sync-external-store "^1.0.0"
 
 react-router-dom@^4.1.1:
   version "4.3.1"
@@ -9228,6 +9224,14 @@ react-select@^5.3.2:
     prop-types "^15.6.0"
     react-transition-group "^4.3.0"
 
+react-shallow-renderer@^16.15.0:
+  version "16.15.0"
+  resolved "https://registry.yarnpkg.com/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz#48fb2cf9b23d23cde96708fe5273a7d3446f4457"
+  integrity sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==
+  dependencies:
+    object-assign "^4.1.1"
+    react-is "^16.12.0 || ^17.0.0 || ^18.0.0"
+
 react-sparklines@^1.7.0:
   version "1.7.0"
   resolved "https://registry.yarnpkg.com/react-sparklines/-/react-sparklines-1.7.0.tgz#9b1d97e8c8610095eeb2ad658d2e1fcf91f91a60"
@@ -9266,15 +9270,14 @@ react-swipeable-views@^0.14.0:
     react-swipeable-views-utils "^0.14.0"
     warning "^4.0.1"
 
-react-test-renderer@^16.14.0:
-  version "16.14.0"
-  resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.14.0.tgz#e98360087348e260c56d4fe2315e970480c228ae"
-  integrity sha512-L8yPjqPE5CZO6rKsKXRO/rVPiaCOy0tQQJbC+UjPNlobl5mad59lvPjwFsQHTvL03caVDIVr9x9/OSgDe6I5Eg==
+react-test-renderer@^18.1.0:
+  version "18.1.0"
+  resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-18.1.0.tgz#35b75754834cf9ab517b6813db94aee0a6b545c3"
+  integrity sha512-OfuueprJFW7h69GN+kr4Ywin7stcuqaYAt1g7airM5cUgP0BoF5G5CXsPGmXeDeEkncb2fqYNECO4y18sSqphg==
   dependencies:
-    object-assign "^4.1.1"
-    prop-types "^15.6.2"
-    react-is "^16.8.6"
-    scheduler "^0.19.1"
+    react-is "^18.1.0"
+    react-shallow-renderer "^16.15.0"
+    scheduler "^0.22.0"
 
 react-textarea-autosize@^8.3.4:
   version "8.3.4"
@@ -9312,14 +9315,12 @@ react-transition-group@^4.3.0:
     loose-envify "^1.4.0"
     prop-types "^15.6.2"
 
-react@^16.14.0:
-  version "16.14.0"
-  resolved "https://registry.yarnpkg.com/react/-/react-16.14.0.tgz#94d776ddd0aaa37da3eda8fc5b6b18a4c9a3114d"
-  integrity sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==
+react@^18.1.0:
+  version "18.1.0"
+  resolved "https://registry.yarnpkg.com/react/-/react-18.1.0.tgz#6f8620382decb17fdc5cc223a115e2adbf104890"
+  integrity sha512-4oL8ivCz5ZEPyclFQXaNksK3adutVS8l2xzZU0cqEFrE9Sb7fC0EFK5uEk74wIreL1DERyjvsU915j1pcT2uEQ==
   dependencies:
     loose-envify "^1.1.0"
-    object-assign "^4.1.1"
-    prop-types "^15.6.2"
 
 read-pkg-up@^7.0.1:
   version "7.0.1"
@@ -9420,7 +9421,7 @@ redux-thunk@^2.4.1:
   resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.4.1.tgz#0dd8042cf47868f4b29699941de03c9301a75714"
   integrity sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==
 
-redux@^4.0.0, redux@^4.2.0:
+redux@^4.2.0:
   version "4.2.0"
   resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.0.tgz#46f10d6e29b6666df758780437651eeb2b969f13"
   integrity sha512-oSBmcKKIuIR4ME29/AeNUnl5L+hvBq7OaJWzaptTQJAntaPvxIJqfnjbaEiCzzaIz+XmVILfqAM3Ob0aXLPfjA==
@@ -9761,13 +9762,12 @@ saxes@^6.0.0:
   dependencies:
     xmlchars "^2.2.0"
 
-scheduler@^0.19.1:
-  version "0.19.1"
-  resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196"
-  integrity sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==
+scheduler@^0.22.0:
+  version "0.22.0"
+  resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.22.0.tgz#83a5d63594edf074add9a7198b1bae76c3db01b8"
+  integrity sha512-6QAm1BgQI88NPYymgGQLCZgvep4FyePDWFpXVK+zNSUgHwlqpJy8VEh8Et0KxTACS4VWwMousBElAZOH9nkkoQ==
   dependencies:
     loose-envify "^1.1.0"
-    object-assign "^4.1.1"
 
 schema-utils@^1.0.0:
   version "1.0.0"
@@ -11158,6 +11158,11 @@ use-latest@^1.2.1:
   dependencies:
     use-isomorphic-layout-effect "^1.1.1"
 
+use-sync-external-store@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.1.0.tgz#3343c3fe7f7e404db70f8c687adf5c1652d34e82"
+  integrity sha512-SEnieB2FPKEVne66NpXPd1Np4R1lTNKfjuy3XdIoPQKYBAFdzbzSZlSn1KJZUiihQLQC5Znot4SBz1EOTBwQAQ==
+
 use@^3.1.0:
   version "3.1.1"
   resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
-- 
GitLab