diff --git a/native/chat/chat-thread-list.react.js b/native/chat/chat-thread-list.react.js
--- a/native/chat/chat-thread-list.react.js
+++ b/native/chat/chat-thread-list.react.js
@@ -129,6 +129,11 @@
   +onScroll: (event: ScrollEvent) => void,
   +onSwipeableWillOpen: (threadInfo: ThreadInfo) => void,
   +composeThread: () => void,
+  +onSearchCancel: () => void,
+  +onSearchFocus: () => void,
+  +renderSearch: (
+    additionalProps?: $Shape<React.ElementConfig<typeof Search>>,
+  ) => React.Node,
 };
 
 class ChatThreadList extends React.PureComponent<Props> {
@@ -185,7 +190,7 @@
       return false;
     }
 
-    this.onSearchCancel();
+    this.props.onSearchCancel();
     return true;
   };
 
@@ -229,73 +234,6 @@
     }
   };
 
-  onSearchFocus = () => {
-    if (this.props.searchStatus !== 'inactive') {
-      return;
-    }
-    if (this.props.scrollPos.current === 0) {
-      this.props.setSearchStatus('active');
-    } else {
-      this.props.setSearchStatus('activating');
-    }
-  };
-
-  clearSearch() {
-    const { flatList } = this;
-    flatList && flatList.scrollToOffset({ offset: 0, animated: false });
-    this.props.setSearchStatus('inactive');
-  }
-
-  onSearchBlur = () => {
-    if (this.props.searchStatus !== 'active') {
-      return;
-    }
-    this.clearSearch();
-  };
-
-  onSearchCancel = () => {
-    this.props.onChangeSearchText('');
-    this.clearSearch();
-  };
-
-  renderSearch(additionalProps?: $Shape<React.ElementConfig<typeof Search>>) {
-    const animatedSearchBoxStyle: AnimatedStyleObj = {
-      marginRight: this.props.searchCancelButtonOffset,
-    };
-    const searchBoxStyle = [
-      this.props.styles.searchBox,
-      animatedSearchBoxStyle,
-    ];
-    const buttonStyle = [
-      this.props.styles.cancelSearchButtonText,
-      { opacity: this.props.searchCancelButtonProgress },
-    ];
-    return (
-      <View style={this.props.styles.searchContainer}>
-        <Button
-          onPress={this.onSearchCancel}
-          disabled={this.props.searchStatus !== 'active'}
-          style={this.props.styles.cancelSearchButton}
-        >
-          {/* eslint-disable react-native/no-raw-text */}
-          <Animated.Text style={buttonStyle}>Cancel</Animated.Text>
-          {/* eslint-enable react-native/no-raw-text */}
-        </Button>
-        <AnimatedView style={searchBoxStyle}>
-          <Search
-            searchText={this.props.searchText}
-            onChangeText={this.props.onChangeSearchText}
-            containerStyle={this.props.styles.search}
-            onBlur={this.onSearchBlur}
-            placeholder="Search chats"
-            ref={this.searchInputRef}
-            {...additionalProps}
-          />
-        </AnimatedView>
-      </View>
-    );
-  }
-
   searchInputRef = (searchInput: ?React.ElementRef<typeof TextInput>) => {
     this.searchInput = searchInput;
   };
@@ -304,8 +242,8 @@
     const item = row.item;
     if (item.type === 'search') {
       return (
-        <TouchableWithoutFeedback onPress={this.onSearchFocus}>
-          {this.renderSearch({ active: false })}
+        <TouchableWithoutFeedback onPress={this.props.onSearchFocus}>
+          {this.props.renderSearch({ active: false })}
         </TouchableWithoutFeedback>
       );
     }
@@ -403,7 +341,7 @@
     let fixedSearch;
     const { searchStatus } = this.props;
     if (searchStatus === 'active') {
-      fixedSearch = this.renderSearch({ autoFocus: true });
+      fixedSearch = this.props.renderSearch({ autoFocus: true });
     }
     const scrollEnabled =
       searchStatus === 'inactive' || searchStatus === 'active';
@@ -606,6 +544,94 @@
     navigateToThread({ threadInfo, searching: true });
   }, [loggedInUserInfo, navigateToThread]);
 
+  const onSearchFocus = React.useCallback(() => {
+    if (searchStatus !== 'inactive') {
+      return;
+    }
+    if (scrollPos.current === 0) {
+      setSearchStatus('active');
+    } else {
+      setSearchStatus('activating');
+    }
+  }, [searchStatus]);
+
+  const clearSearch = React.useCallback(() => {
+    // TODO (atul): Scroll to top of flatList (animated: false)
+    setSearchStatus('inactive');
+  }, []);
+
+  const onSearchBlur = React.useCallback(() => {
+    if (searchStatus !== 'active') {
+      return;
+    }
+    clearSearch();
+  }, [clearSearch, searchStatus]);
+
+  const onSearchCancel = React.useCallback(() => {
+    onChangeSearchText('');
+    clearSearch();
+  }, [clearSearch, onChangeSearchText]);
+
+  const animatedSearchBoxStyle: AnimatedStyleObj = React.useMemo(
+    () => ({
+      marginRight: searchCancelButtonOffset,
+    }),
+    [searchCancelButtonOffset],
+  );
+
+  const searchBoxStyle = React.useMemo(
+    () => [styles.searchBox, animatedSearchBoxStyle],
+    [animatedSearchBoxStyle, styles.searchBox],
+  );
+
+  const buttonStyle = React.useMemo(
+    () => [
+      styles.cancelSearchButtonText,
+      { opacity: searchCancelButtonProgress },
+    ],
+    [searchCancelButtonProgress, styles.cancelSearchButtonText],
+  );
+
+  const searchInputRef = React.useRef();
+  const renderSearch = React.useCallback(
+    (additionalProps?: $Shape<React.ElementConfig<typeof Search>>) => (
+      <View style={styles.searchContainer}>
+        <Button
+          onPress={onSearchCancel}
+          disabled={searchStatus !== 'active'}
+          style={styles.cancelSearchButton}
+        >
+          {/* eslint-disable react-native/no-raw-text */}
+          <Animated.Text style={buttonStyle}>Cancel</Animated.Text>
+          {/* eslint-enable react-native/no-raw-text */}
+        </Button>
+        <AnimatedView style={searchBoxStyle}>
+          <Search
+            searchText={searchText}
+            onChangeText={onChangeSearchText}
+            containerStyle={styles.search}
+            onBlur={onSearchBlur}
+            placeholder="Search chats"
+            ref={searchInputRef}
+            {...additionalProps}
+          />
+        </AnimatedView>
+      </View>
+    ),
+    [
+      buttonStyle,
+      onChangeSearchText,
+      onSearchBlur,
+      onSearchCancel,
+      searchBoxStyle,
+      searchStatus,
+      searchText,
+      styles.cancelSearchButton,
+      styles.search,
+      styles.searchContainer,
+    ],
+  );
+
   return (
     <ChatThreadList
       navigation={navigation}
@@ -640,6 +666,9 @@
       onScroll={onScroll}
       onSwipeableWillOpen={onSwipeableWillOpen}
       composeThread={composeThread}
+      onSearchCancel={onSearchCancel}
+      onSearchFocus={onSearchFocus}
+      renderSearch={renderSearch}
     />
   );
 }