prevent duplicate search when navigating back with a new hashtag (#9579)
Tapping a hashtag while search screen was showing previous results will cause both useEffect and useDidUpdate to fire causing two concurrent search calls. This guard prevents that scenario.
This commit is contained in:
parent
5365109ca8
commit
82e5ff2ae8
2 changed files with 57 additions and 0 deletions
|
|
@ -75,6 +75,10 @@ describe('SearchScreen', () => {
|
|||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('renders search screen correctly', () => {
|
||||
const {getByTestId, getByText, getByPlaceholderText} = renderWithEverything(
|
||||
<SearchScreen {...baseProps}/>,
|
||||
|
|
@ -238,6 +242,54 @@ describe('SearchScreen', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('should not trigger a duplicate search via useDidUpdate when refocused with a new searchTerm', async () => {
|
||||
let currentIsFocused = false;
|
||||
let currentSearchTerm = '#old';
|
||||
|
||||
jest.spyOn(require('@react-navigation/native'), 'useIsFocused').mockImplementation(() => currentIsFocused);
|
||||
jest.spyOn(require('@react-navigation/native'), 'useNavigation').mockImplementation(() => ({
|
||||
getState: () => ({
|
||||
index: 0,
|
||||
routes: [{params: {searchTerm: currentSearchTerm}}],
|
||||
}),
|
||||
}));
|
||||
|
||||
const {rerender} = renderWithEverything(<SearchScreen {...baseProps}/>, {database});
|
||||
|
||||
// Initial focus with #old triggers useEffect search
|
||||
await act(async () => {
|
||||
currentIsFocused = true;
|
||||
rerender(<SearchScreen {...baseProps}/>);
|
||||
});
|
||||
|
||||
await waitFor(() => expect(searchPosts).toHaveBeenCalledWith(
|
||||
expect.any(String), 'team1', expect.objectContaining({terms: '#old'}),
|
||||
));
|
||||
|
||||
// Navigate away
|
||||
await act(async () => {
|
||||
currentIsFocused = false;
|
||||
rerender(<SearchScreen {...baseProps}/>);
|
||||
});
|
||||
|
||||
jest.clearAllMocks();
|
||||
|
||||
// Navigate back with a new hashtag — useDidUpdate and useEffect both fire,
|
||||
// but useDidUpdate guard should skip since searchTerm !== lastSearchedValue
|
||||
await act(async () => {
|
||||
currentSearchTerm = '#new';
|
||||
currentIsFocused = true;
|
||||
rerender(<SearchScreen {...baseProps}/>);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(searchPosts).toHaveBeenCalledTimes(1);
|
||||
expect(searchPosts).toHaveBeenCalledWith(
|
||||
expect.any(String), 'team1', expect.objectContaining({terms: '#new'}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('populates searchTerm when navigating to screen with hashtag', async () => {
|
||||
const mockNavigation = {
|
||||
getState: () => ({
|
||||
|
|
|
|||
|
|
@ -398,6 +398,11 @@ const SearchScreen = ({teamId, teams, crossTeamSearchEnabled}: Props) => {
|
|||
}, [isFocused]);
|
||||
|
||||
useDidUpdate(() => {
|
||||
if (searchTerm && searchTerm !== lastSearchedValue) {
|
||||
// searchTerm changed (case for hashtag tap) — useEffect handles it; skip to avoid double search
|
||||
return;
|
||||
}
|
||||
|
||||
if (isFocused && lastSearchedValue && showResults) {
|
||||
// requestAnimationFrame for smooth UI updates
|
||||
requestAnimationFrame(() => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue