diff --git a/app/screens/home/search/search.test.tsx b/app/screens/home/search/search.test.tsx
index bb9f0c344..f0f493ad3 100644
--- a/app/screens/home/search/search.test.tsx
+++ b/app/screens/home/search/search.test.tsx
@@ -204,4 +204,65 @@ describe('SearchScreen', () => {
expect.any(String),
);
});
+
+ it('does not restore searchTerm after clearing when navigated with hashtag', async () => {
+ const mockNavigation = {
+ getState: () => ({
+ index: 0,
+ routes: [{params: {searchTerm: '#hashtag'}}],
+ }),
+ };
+
+ jest.spyOn(require('@react-navigation/native'), 'useNavigation').mockReturnValue(mockNavigation);
+
+ const {getByTestId} = renderWithEverything(
+ ,
+ {database},
+ );
+
+ await waitFor(() => {
+ const searchInput = getByTestId('navigation.header.search_bar.search.input');
+ expect(searchInput.props.value).toBe('#hashtag');
+ });
+
+ const searchInput = getByTestId('navigation.header.search_bar.search.input');
+ const clearButton = getByTestId('navigation.header.search_bar.search.clear.button');
+
+ act(() => {
+ fireEvent.press(clearButton);
+ });
+
+ await waitFor(() => {
+ expect(searchInput.props.value).toBe('');
+ });
+ });
+
+ it('populates searchTerm when navigating to screen with hashtag', async () => {
+ const mockNavigation = {
+ getState: () => ({
+ index: 0,
+ routes: [{params: {searchTerm: '#newtag'}}],
+ }),
+ };
+
+ jest.spyOn(require('@react-navigation/native'), 'useNavigation').mockReturnValue(mockNavigation);
+
+ const {getByTestId} = renderWithEverything(
+ ,
+ {database},
+ );
+
+ await waitFor(() => {
+ const searchInput = getByTestId('navigation.header.search_bar.search.input');
+ expect(searchInput.props.value).toBe('#newtag');
+ });
+
+ await waitFor(() => {
+ expect(searchPosts).toHaveBeenCalledWith(
+ expect.any(String),
+ 'team1',
+ expect.objectContaining({terms: '#newtag'}),
+ );
+ });
+ });
});
diff --git a/app/screens/home/search/search.tsx b/app/screens/home/search/search.tsx
index b5e9b97d6..0db55e6e7 100644
--- a/app/screens/home/search/search.tsx
+++ b/app/screens/home/search/search.tsx
@@ -112,6 +112,7 @@ const SearchScreen = ({teamId, teams, crossTeamSearchEnabled}: Props) => {
const clearRef = useRef(false);
const cancelRef = useRef(false);
const searchRef = useRef(null);
+ const processedSearchTermRef = useRef('');
const [cursorPosition, setCursorPosition] = useState(searchTerm?.length || 0);
const [searchValue, setSearchValue] = useState(searchTerm || '');
@@ -137,6 +138,7 @@ const SearchScreen = ({teamId, teams, crossTeamSearchEnabled}: Props) => {
const onSnap = useCallback((offset: number, animated = true) => {
scrollRef.current?.scrollToOffset({offset, animated});
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- scrollRef is a ref object, so its reference should not change between renders
}, []);
const onSnapWithTimeout = useCallback((offset: number, animated = true) => {
@@ -365,7 +367,8 @@ const SearchScreen = ({teamId, teams, crossTeamSearchEnabled}: Props) => {
}, [unlock, onSnapWithTimeout]);
useEffect(() => {
- if (searchTerm) {
+ if (searchTerm && searchTerm !== processedSearchTermRef.current) {
+ processedSearchTermRef.current = searchTerm;
clearInputs();
setSearchValue(searchTerm);
handleSearch(searchTeamId, searchTerm);
@@ -379,6 +382,7 @@ const SearchScreen = ({teamId, teams, crossTeamSearchEnabled}: Props) => {
}, 300);
} else {
setAutoScroll(false);
+ processedSearchTermRef.current = '';
}
}, [isFocused]);