react-navigation-shared-element
react-navigation-shared-element copied to clipboard
Yelp-like search
@IjzerenHein thanks a lot for this great lib! Started playing around with it and I'm really excited about it.
I'm trying to share a search field between two screens. Almost identical to the way Yelp works, actually. The first screen is the map with the search field on top. When you click the search field, it should morph into the second search screen where you type the search term or select some default search category.
Sounds simple, but I'm having some trouble making it work, or rather, making it work well.
Here is what I'm doing right now:
I have an expo app with bottom tab navigator (TS). Let me paste only the important parts:
export default function BottomTabNavigator() {
return (
<BottomTab.Navigator initialRouteName="Search">
<BottomTab.Screen
name="Search"
component={SearchNavigator}
...
const SearchStack = createSharedElementStackNavigator<SearchParamList>();
function SearchNavigator() {
return (
<SearchStack.Navigator headerMode="none">
<SearchStack.Screen name="SearchScreen" component={SearchScreen} />
<SearchStack.Screen name="SearchFocusScreen" component={SearchFocusScreen} />
</SearchStack.Navigator>
);
}
SearchScreen
const [searchQuery, setSearchQuery] = useState('');
// If we returned from the second search screen with a search term, set it in state.
useEffect(() => {
if (route.params) {
setSearchQuery(route.params.searchTerm);
}
}, [route]);
const searchRef = useRef(null);
const onFocus = () => {
// Morph into the second search screen. If we have a search term, pass it along. Then blur the input so we don't loop back.
if (route.params) {
setSearchQuery(route.params.searchTerm);
navigation.navigate('SearchFocusScreen', { searchTerm: searchQuery });
} else {
navigation.navigate('SearchFocusScreen');
}
searchRef.current.blur();
};
return (
<View>
<MapView ... />
<View>
<SafeAreaView>
<SharedElement id="searchBar" style={styles.searchContainer}>
<Searchbar
ref={searchRef}
placeholder="Search"
value={searchQuery}
onSubmitEditing={() => {
initSearch({ searchQuery, region });
}}
onFocus={onFocus}
/>
Second search screen
const [searchQuery, setSearchQuery] = useState('');
const searchRef = useRef(null);
useEffect(() => {
searchRef.current.focus();
if (route.params) {
setSearchQuery(route.params.searchTerm);
}
}, [route]);
return (
<SafeAreaView>
<View>
<SharedElement id="searchBar" style={styles.searchContainer}>
<Searchbar
ref={searchRef}
placeholder="Search"
onChangeText={(query) => setSearchQuery(query)}
value={searchQuery}
onSubmitEditing={() => {
navigation.navigate('SearchScreen', { searchTerm: searchQuery }); // Pass the search query back to Search page 1
}}
...
Mind you, I haven't yet finished doing the actual transition, but I know that part will work just fine. I am more concerned with the logistics of the above.
Does it work? Yes. But it feels wrong. Also - there's an issue that when I type with an error into the search field in search screen 2, I get auto-correct suggestions. If I then quickly click Search, it auto corrects the typo after sending the error to search screen 1. And it's visible.
Could you please help with this common case and help me with my code or suggest a cleaner one altogether?
Really appreciate it!