diff --git a/client/modules/IDE/components/SketchList.jsx b/client/modules/IDE/components/SketchList.jsx
index bce30da1dc..0dc02bd2db 100644
--- a/client/modules/IDE/components/SketchList.jsx
+++ b/client/modules/IDE/components/SketchList.jsx
@@ -1,5 +1,5 @@
+import React, { useState, useRef } from 'react';
 import PropTypes from 'prop-types';
-import React from 'react';
 import { Helmet } from 'react-helmet';
 import { withTranslation } from 'react-i18next';
 import { connect } from 'react-redux';
@@ -30,121 +30,108 @@ const ROOT_URL = getConfig('API_URL');
 const formatDateCell = (date, mobile = false) =>
   dates.format(date, { showTime: !mobile });
 
-class SketchListRowBase extends React.Component {
-  constructor(props) {
-    super(props);
-    this.state = {
-      optionsOpen: false,
-      renameOpen: false,
-      renameValue: props.sketch.name,
-      isFocused: false
-    };
-    this.renameInput = React.createRef();
-  }
-
-  onFocusComponent = () => {
-    this.setState({ isFocused: true });
+const SketchListRowBase = ({
+  sketch,
+  username,
+  mobile,
+  user,
+  changeProjectName,
+  cloneProject,
+  showShareModal,
+  deleteProject,
+  onAddToCollection,
+  handleRowClick,
+  t
+}) => {
+  const [optionsOpen, setOptionsOpen] = useState(false);
+  const [renameOpen, setRenameOpen] = useState(false);
+  const [renameValue, setRenameValue] = useState(sketch.name);
+  const [isFocused, setIsFocused] = useState(false);
+  const renameInput = useRef(null);
+
+  const closeAll = () => {
+    setRenameOpen(false);
+    setOptionsOpen(false);
   };
 
-  onBlurComponent = () => {
-    this.setState({ isFocused: false });
+  const updateName = () => {
+    const isValid = renameValue.trim().length !== 0;
+    if (isValid) {
+      changeProjectName(sketch.id, renameValue.trim());
+    }
+  };
+
+  const onFocusComponent = () => {
+    setIsFocused(true);
+  };
+
+  const onBlurComponent = () => {
+    setIsFocused(false);
     setTimeout(() => {
-      if (!this.state.isFocused) {
-        this.closeAll();
+      if (!isFocused) {
+        closeAll();
       }
     }, 200);
   };
 
-  openOptions = () => {
-    this.setState({
-      optionsOpen: true
-    });
+  const openOptions = () => {
+    setOptionsOpen(true);
   };
 
-  closeOptions = () => {
-    this.setState({
-      optionsOpen: false
-    });
+  const closeOptions = () => {
+    setOptionsOpen(false);
   };
 
-  toggleOptions = () => {
-    if (this.state.optionsOpen) {
-      this.closeOptions();
+  const toggleOptions = () => {
+    if (optionsOpen) {
+      closeOptions();
     } else {
-      this.openOptions();
+      openOptions();
     }
   };
 
-  openRename = () => {
-    this.setState(
-      {
-        renameOpen: true,
-        renameValue: this.props.sketch.name
-      },
-      () => this.renameInput.current.focus()
-    );
+  const openRename = () => {
+    setRenameOpen(true);
+    setRenameValue(sketch.name);
+    renameInput.current.focus();
   };
 
-  closeRename = () => {
-    this.setState({
-      renameOpen: false
-    });
+  const closeRename = () => {
+    setRenameOpen(false);
   };
 
-  closeAll = () => {
-    this.setState({
-      renameOpen: false,
-      optionsOpen: false
-    });
-  };
-
-  handleRenameChange = (e) => {
-    this.setState({
-      renameValue: e.target.value
-    });
+  const handleRenameChange = (e) => {
+    setRenameValue(e.target.value);
   };
 
-  handleRenameEnter = (e) => {
+  const handleRenameEnter = (e) => {
     if (e.key === 'Enter') {
-      this.updateName();
-      this.closeAll();
+      updateName();
+      closeAll();
     }
   };
 
-  handleRenameBlur = () => {
-    this.updateName();
-    this.closeAll();
+  const handleRenameBlur = () => {
+    updateName();
+    closeAll();
   };
 
-  updateName = () => {
-    const isValid = this.state.renameValue.trim().length !== 0;
-    if (isValid) {
-      this.props.changeProjectName(
-        this.props.sketch.id,
-        this.state.renameValue.trim()
-      );
-    }
+  const resetSketchName = () => {
+    setRenameValue(sketch.name);
+    setRenameOpen(false);
   };
 
-  resetSketchName = () => {
-    this.setState({
-      renameValue: this.props.sketch.name,
-      renameOpen: false
-    });
+  const handleDropdownOpen = () => {
+    closeAll();
+    openOptions();
   };
 
-  handleDropdownOpen = () => {
-    this.closeAll();
-    this.openOptions();
+  const handleRenameOpen = () => {
+    closeAll();
+    openRename();
   };
 
-  handleRenameOpen = () => {
-    this.closeAll();
-    this.openRename();
-  };
-
-  handleSketchDownload = () => {
-    const { sketch } = this.props;
+  const handleSketchDownload = () => {
     const downloadLink = document.createElement('a');
     downloadLink.href = `${ROOT_URL}/projects/${sketch.id}/zip`;
     downloadLink.download = `${sketch.name}.zip`;
@@ -153,53 +140,48 @@ class SketchListRowBase extends React.Component {
     document.body.removeChild(downloadLink);
   };
 
-  handleSketchDuplicate = () => {
-    this.closeAll();
-    this.props.cloneProject(this.props.sketch);
+  const handleSketchDuplicate = () => {
+    closeAll();
+    cloneProject(sketch);
   };
 
-  handleSketchShare = () => {
-    this.closeAll();
-    this.props.showShareModal(
-      this.props.sketch.id,
-      this.props.sketch.name,
-      this.props.username
-    );
+  const handleSketchShare = () => {
+    closeAll();
+    showShareModal(sketch.id, sketch.name, username);
   };
 
-  handleSketchDelete = () => {
-    this.closeAll();
+  const handleSketchDelete = () => {
+    closeAll();
     if (
       window.confirm(
-        this.props.t('Common.DeleteConfirmation', {
-          name: this.props.sketch.name
+        t('Common.DeleteConfirmation', {
+          name: sketch.name
         })
       )
     ) {
-      this.props.deleteProject(this.props.sketch.id);
+      deleteProject(sketch.id);
     }
   };
 
-  renderViewButton = (sketchURL) => (
+  const renderViewButton = (sketchURL) => (
     <td className="sketch-list__dropdown-column">
-      <Link to={sketchURL}>{this.props.t('SketchList.View')}</Link>
+      <Link to={sketchURL}>{t('SketchList.View')}</Link>
     </td>
   );
 
-  renderDropdown = () => {
-    const { optionsOpen } = this.state;
-    const userIsOwner = this.props.user.username === this.props.username;
+  const renderDropdown = () => {
+    const userIsOwner = user.username === username;
 
     return (
       <td className="sketch-list__dropdown-column">
         <button
           className="sketch-list__dropdown-button"
-          onClick={this.toggleOptions}
-          onBlur={this.onBlurComponent}
-          onFocus={this.onFocusComponent}
-          aria-label={this.props.t('SketchList.ToggleLabelARIA')}
+          onClick={toggleOptions}
+          onBlur={onBlurComponent}
+          onFocus={onFocusComponent}
+          aria-label={t('SketchList.ToggleLabelARIA')}
         >
-          {this.props.mobile ? (
+          {mobile ? (
             <MoreIconSvg focusable="false" aria-hidden="true" />
           ) : (
             <DownFilledTriangleIcon focusable="false" aria-hidden="true" />
@@ -211,57 +193,57 @@ class SketchListRowBase extends React.Component {
               <li>
                 <button
                   className="sketch-list__action-option"
-                  onClick={this.handleRenameOpen}
-                  onBlur={this.onBlurComponent}
-                  onFocus={this.onFocusComponent}
+                  onClick={handleRenameOpen}
+                  onBlur={onBlurComponent}
+                  onFocus={onFocusComponent}
                 >
-                  {this.props.t('SketchList.DropdownRename')}
+                  {t('SketchList.DropdownRename')}
                 </button>
               </li>
             )}
             <li>
               <button
                 className="sketch-list__action-option"
-                onClick={this.handleSketchDownload}
-                onBlur={this.onBlurComponent}
-                onFocus={this.onFocusComponent}
+                onClick={handleSketchDownload}
+                onBlur={onBlurComponent}
+                onFocus={onFocusComponent}
               >
-                {this.props.t('SketchList.DropdownDownload')}
+                {t('SketchList.DropdownDownload')}
               </button>
             </li>
-            {this.props.user.authenticated && (
+            {user.authenticated && (
               <li>
                 <button
                   className="sketch-list__action-option"
-                  onClick={this.handleSketchDuplicate}
-                  onBlur={this.onBlurComponent}
-                  onFocus={this.onFocusComponent}
+                  onClick={handleSketchDuplicate}
+                  onBlur={onBlurComponent}
+                  onFocus={onFocusComponent}
                 >
-                  {this.props.t('SketchList.DropdownDuplicate')}
+                  {t('SketchList.DropdownDuplicate')}
                 </button>
               </li>
             )}
-            {this.props.user.authenticated && (
+            {user.authenticated && (
               <li>
                 <button
                   className="sketch-list__action-option"
                   onClick={() => {
-                    this.props.onAddToCollection();
-                    this.closeAll();
+                    onAddToCollection();
+                    closeAll();
                   }}
-                  onBlur={this.onBlurComponent}
-                  onFocus={this.onFocusComponent}
+                  onBlur={onBlurComponent}
+                  onFocus={onFocusComponent}
                 >
-                  {this.props.t('SketchList.DropdownAddToCollection')}
+                  {t('SketchList.DropdownAddToCollection')}
                 </button>
               </li>
             )}
             {/* <li>
               <button
                 className="sketch-list__action-option"
-                onClick={this.handleSketchShare}
-                onBlur={this.onBlurComponent}
-                onFocus={this.onFocusComponent}
+                onClick={handleSketchShare}
+                onBlur={onBlurComponent}
+                onFocus={onFocusComponent}
               >
                 Share
               </button>
@@ -270,11 +252,11 @@ class SketchListRowBase extends React.Component {
               <li>
                 <button
                   className="sketch-list__action-option"
-                  onClick={this.handleSketchDelete}
-                  onBlur={this.onBlurComponent}
-                  onFocus={this.onFocusComponent}
+                  onClick={handleSketchDelete}
+                  onBlur={onBlurComponent}
+                  onFocus={onFocusComponent}
                 >
-                  {this.props.t('SketchList.DropdownDelete')}
+                  {t('SketchList.DropdownDelete')}
                 </button>
               </li>
             )}
@@ -284,46 +266,42 @@ class SketchListRowBase extends React.Component {
     );
   };
 
-  render() {
-    const { sketch, username, mobile } = this.props;
-    const { renameOpen, renameValue } = this.state;
-    let url = `/${username}/sketches/${sketch.id}`;
-    if (username === 'p5') {
-      url = `/${username}/sketches/${slugify(sketch.name, '_')}`;
-    }
-
-    const name = (
-      <React.Fragment>
-        <Link to={url}>{renameOpen ? '' : sketch.name}</Link>
-        {renameOpen && (
-          <input
-            value={renameValue}
-            onChange={this.handleRenameChange}
-            onKeyUp={this.handleRenameEnter}
-            onBlur={this.handleRenameBlur}
-            onClick={(e) => e.stopPropagation()}
-            ref={this.renameInput}
-          />
-        )}
-      </React.Fragment>
-    );
+  const url =
+    username === 'p5'
+      ? `/${username}/sketches/${slugify(sketch.name, '_')}`
+      : `/${username}/sketches/${sketch.id}`;
+
+  const name = (
+    <React.Fragment>
+      <Link to={url}>{renameOpen ? '' : sketch.name}</Link>
+      {renameOpen && (
+        <input
+          value={renameValue}
+          onChange={handleRenameChange}
+          onKeyUp={handleRenameEnter}
+          onBlur={handleRenameBlur}
+          onClick={(e) => e.stopPropagation()}
+          ref={renameInput}
+        />
+      )}
+    </React.Fragment>
+  );
 
-    return (
-      <React.Fragment>
-        <tr
-          className="sketches-table__row"
-          key={sketch.id}
-          onClick={this.handleRowClick}
-        >
-          <th scope="row">{name}</th>
-          <td>{formatDateCell(sketch.createdAt, mobile)}</td>
-          <td>{formatDateCell(sketch.updatedAt, mobile)}</td>
-          {this.renderDropdown()}
-        </tr>
-      </React.Fragment>
-    );
-  }
-}
+  return (
+    <React.Fragment>
+      <tr
+        className="sketches-table__row"
+        key={sketch.id}
+        onClick={() => handleRowClick(sketch)}
+      >
+        <th scope="row">{name}</th>
+        <td>{formatDateCell(sketch.createdAt, mobile)}</td>
+        <td>{formatDateCell(sketch.updatedAt, mobile)}</td>
+        {renderDropdown()}
+      </tr>
+    </React.Fragment>
+  );
+};
 
 SketchListRowBase.propTypes = {
   sketch: PropTypes.shape({
@@ -343,6 +321,7 @@ SketchListRowBase.propTypes = {
   changeProjectName: PropTypes.func.isRequired,
   onAddToCollection: PropTypes.func.isRequired,
   mobile: PropTypes.bool,
+  handleRowClick: PropTypes.func.isRequired,
   t: PropTypes.func.isRequired
 };
 
@@ -350,111 +329,94 @@ SketchListRowBase.defaultProps = {
   mobile: false
 };
 
-function mapDispatchToPropsSketchListRow(dispatch) {
-  return bindActionCreators(
-    Object.assign({}, ProjectActions, IdeActions),
-    dispatch
-  );
-}
-
-const SketchListRow = connect(
-  null,
-  mapDispatchToPropsSketchListRow
-)(SketchListRowBase);
-
-class SketchList extends React.Component {
-  constructor(props) {
-    super(props);
-    this.props.getProjects(this.props.username);
-    this.props.resetSorting();
-
-    this.state = {
-      isInitialDataLoad: true
-    };
-  }
-
-  componentDidUpdate(prevProps) {
-    if (
-      this.props.sketches !== prevProps.sketches &&
-      Array.isArray(this.props.sketches)
-    ) {
-      // eslint-disable-next-line react/no-did-update-set-state
-      this.setState({
-        isInitialDataLoad: false
-      });
+const SketchList = ({
+  user,
+  getProjects,
+  sketches,
+  username,
+  loading,
+  toggleDirectionForField,
+  resetSorting,
+  sorting,
+  mobile,
+  t
+}) => {
+  getProjects(username);
+  resetSorting();
+
+  const [isInitialDataLoad, setIsInitialDataLoad] = useState(true);
+  const [sketchToAddToCollection, setSketchToAddToCollection] = useState(null);
+
+  React.useEffect(() => {
+    if (Array.isArray(sketches)) {
+      setIsInitialDataLoad(false);
     }
-  }
+  }, [sketches]);
 
-  getSketchesTitle() {
-    if (this.props.username === this.props.user.username) {
-      return this.props.t('SketchList.Title');
+  const getSketchesTitle = () => {
+    if (username === user.username) {
+      return t('SketchList.Title');
     }
-    return this.props.t('SketchList.AnothersTitle', {
-      anotheruser: this.props.username
+    return t('SketchList.AnothersTitle', {
+      anotheruser: username
     });
-  }
+  };
 
-  hasSketches() {
-    return !this.isLoading() && this.props.sketches.length > 0;
-  }
+  const isLoading = () => loading && isInitialDataLoad;
 
-  isLoading() {
-    return this.props.loading && this.state.isInitialDataLoad;
-  }
+  const hasSketches = () => !isLoading() && sketches.length > 0;
 
-  _renderLoader() {
-    if (this.isLoading()) return <Loader />;
+  const renderLoader = () => {
+    if (isLoading()) return <Loader />;
     return null;
-  }
+  };
 
-  _renderEmptyTable() {
-    if (!this.isLoading() && this.props.sketches.length === 0) {
+  const renderEmptyTable = () => {
+    if (!isLoading() && sketches.length === 0) {
       return (
-        <p className="sketches-table__empty">
-          {this.props.t('SketchList.NoSketches')}
-        </p>
+        <p className="sketches-table__empty">{t('SketchList.NoSketches')}</p>
       );
     }
     return null;
-  }
+  };
 
-  _getButtonLabel = (fieldName, displayName) => {
-    const { field, direction } = this.props.sorting;
+  const _getButtonLabel = (fieldName, displayName) => {
+    const { field, direction } = sorting;
     let buttonLabel;
     if (field !== fieldName) {
       if (field === 'name') {
-        buttonLabel = this.props.t('SketchList.ButtonLabelAscendingARIA', {
+        buttonLabel = t('SketchList.ButtonLabelAscendingARIA', {
           displayName
         });
       } else {
-        buttonLabel = this.props.t('SketchList.ButtonLabelDescendingARIA', {
+        buttonLabel = t('SketchList.ButtonLabelDescendingARIA', {
           displayName
         });
       }
     } else if (direction === SortingActions.DIRECTION.ASC) {
-      buttonLabel = this.props.t('SketchList.ButtonLabelDescendingARIA', {
+      buttonLabel = t('SketchList.ButtonLabelDescendingARIA', {
         displayName
       });
     } else {
-      buttonLabel = this.props.t('SketchList.ButtonLabelAscendingARIA', {
+      buttonLabel = t('SketchList.ButtonLabelAscendingARIA', {
         displayName
       });
     }
     return buttonLabel;
   };
 
-  _renderFieldHeader = (fieldName, displayName) => {
-    const { field, direction } = this.props.sorting;
+  const _renderFieldHeader = (fieldName, displayName) => {
+    const { field, direction } = sorting;
     const headerClass = classNames({
       'sketches-table__header': true,
       'sketches-table__header--selected': field === fieldName
     });
-    const buttonLabel = this._getButtonLabel(fieldName, displayName);
+    const buttonLabel = _getButtonLabel(fieldName, displayName);
     return (
       <th scope="col">
         <button
           className="sketch-list__sort-button"
-          onClick={() => this.props.toggleDirectionForField(fieldName)}
+          onClick={() => toggleDirectionForField(fieldName)}
           aria-label={buttonLabel}
         >
           <span className={headerClass}>{displayName}</span>
@@ -462,7 +424,7 @@ class SketchList extends React.Component {
             direction === SortingActions.DIRECTION.ASC && (
               <ArrowUpIcon
                 role="img"
-                aria-label={this.props.t('SketchList.DirectionAscendingARIA')}
+                aria-label={t('SketchList.DirectionAscendingARIA')}
                 focusable="false"
               />
             )}
@@ -470,7 +432,7 @@ class SketchList extends React.Component {
             direction === SortingActions.DIRECTION.DESC && (
               <ArrowDownIcon
                 role="img"
-                aria-label={this.props.t('SketchList.DirectionDescendingARIA')}
+                aria-label={t('SketchList.DirectionDescendingARIA')}
                 focusable="false"
               />
             )}
@@ -479,81 +441,68 @@ class SketchList extends React.Component {
     );
   };
 
-  render() {
-    const username =
-      this.props.username !== undefined
-        ? this.props.username
-        : this.props.user.username;
-    const { mobile } = this.props;
-    return (
-      <article className="sketches-table-container">
-        <Helmet>
-          <title>{this.getSketchesTitle()}</title>
-        </Helmet>
-        {this._renderLoader()}
-        {this._renderEmptyTable()}
-        {this.hasSketches() && (
-          <table
-            className="sketches-table"
-            summary={this.props.t('SketchList.TableSummary')}
-          >
-            <thead>
-              <tr>
-                {this._renderFieldHeader(
-                  'name',
-                  this.props.t('SketchList.HeaderName')
-                )}
-                {this._renderFieldHeader(
-                  'createdAt',
-                  this.props.t('SketchList.HeaderCreatedAt', {
-                    context: mobile ? 'mobile' : ''
-                  })
-                )}
-                {this._renderFieldHeader(
-                  'updatedAt',
-                  this.props.t('SketchList.HeaderUpdatedAt', {
-                    context: mobile ? 'mobile' : ''
-                  })
-                )}
-                <th scope="col"></th>
-              </tr>
-            </thead>
-            <tbody>
-              {this.props.sketches.map((sketch) => (
-                <SketchListRow
-                  mobile={mobile}
-                  key={sketch.id}
-                  sketch={sketch}
-                  user={this.props.user}
-                  username={username}
-                  onAddToCollection={() => {
-                    this.setState({ sketchToAddToCollection: sketch });
-                  }}
-                  t={this.props.t}
-                />
-              ))}
-            </tbody>
-          </table>
-        )}
-        {this.state.sketchToAddToCollection && (
-          <Overlay
-            isFixedHeight
-            title={this.props.t('SketchList.AddToCollectionOverlayTitle')}
-            closeOverlay={() =>
-              this.setState({ sketchToAddToCollection: null })
-            }
-          >
-            <AddToCollectionList
-              project={this.state.sketchToAddToCollection}
-              username={this.props.username}
-              user={this.props.user}
-            />
-          </Overlay>
-        )}
-      </article>
-    );
-  }
-}
+  return (
+    <article className="sketches-table-container">
+      <Helmet>
+        <title>{getSketchesTitle()}</title>
+      </Helmet>
+      {renderLoader()}
+      {renderEmptyTable()}
+      {hasSketches() && (
+        <table
+          className="sketches-table"
+          summary={t('SketchList.TableSummary')}
+        >
+          <thead>
+            <tr>
+              {_renderFieldHeader('name', t('SketchList.HeaderName'))}
+              {_renderFieldHeader(
+                'createdAt',
+                t('SketchList.HeaderCreatedAt', {
+                  context: mobile ? 'mobile' : ''
+                })
+              )}
+              {_renderFieldHeader(
+                'updatedAt',
+                t('SketchList.HeaderUpdatedAt', {
+                  context: mobile ? 'mobile' : ''
+                })
+              )}
+              <th scope="col"></th>
+            </tr>
+          </thead>
+          <tbody>
+            {sketches.map((sketch) => (
+              <SketchListRowBase
+                key={sketch.id}
+                sketch={sketch}
+                user={user}
+                username={username}
+                onAddToCollection={() => {
+                  setSketchToAddToCollection(sketch);
+                }}
+                t={t}
+              />
+            ))}
+          </tbody>
+        </table>
+      )}
+      {sketchToAddToCollection && (
+        <Overlay
+          isFixedHeight
+          title={t('SketchList.AddToCollectionOverlayTitle')}
+          closeOverlay={() => setSketchToAddToCollection(null)}
+        >
+          <AddToCollectionList
+            project={sketchToAddToCollection}
+            username={username}
+            user={user}
+          />
+        </Overlay>
+      )}
+    </article>
+  );
+};
 
 SketchList.propTypes = {
   user: PropTypes.shape({
@@ -586,18 +535,16 @@ SketchList.defaultProps = {
   mobile: false
 };
 
-function mapStateToProps(state) {
-  return {
-    user: state.user,
-    sketches: getSortedSketches(state),
-    sorting: state.sorting,
-    loading: state.loading,
-    project: state.project
-  };
-}
+const mapStateToProps = (state) => ({
+  user: state.user,
+  sketches: getSortedSketches(state),
+  sorting: state.sorting,
+  loading: state.loading,
+  project: state.project
+});
 
-function mapDispatchToProps(dispatch) {
-  return bindActionCreators(
+const mapDispatchToProps = (dispatch) =>
+  bindActionCreators(
     Object.assign(
       {},
       ProjectsActions,
@@ -607,7 +554,6 @@ function mapDispatchToProps(dispatch) {
     ),
     dispatch
   );
-}
 
 export default withTranslation()(
   connect(mapStateToProps, mapDispatchToProps)(SketchList)