I have a parent component called SearchScreen.tsx, within it there are 2 child components, SearchBarView.tsx and SearchResultView.tsx. The SearchBarView has a callback prop onTextChanged(text)
, the text changed will be processed in the SearchScreen and pass the result to SearchResultView. The data passing is working as expected. Every time when new character is entered in SearchBarView, the above scenario will happen, the new text change goes from SearchBarView to SearchScreen, new search result generated and passed to SearchResultView. That means, when a user enters 'abcdefghij' in SearchBarView, this will happen 10 times because there are 10 characters in 'abcdefghij'. Whenever this happens, all 3 components will rerender. In order to reduce the number of changes, I used a debounce while the search phrase is being entered, this will reduce the number of changes/rerenders. However, the rerender still causes a problem in SearchBarView. In SearchBarView, the search phrase is being tracked in a local state like this:
const [searchPhrase, setSearchPhrase] = useState('');
Every time when the parent component SearchScreen re-renders, SearchBarView gets re-rendered, when SearchBarView get re-rendered that is caused by the parent component, it sets the searchPhrase back to empty string because useState('') initializes the searchPhrase to an empty string. So, the problem is in the end, the searchPhrase always ended up with empty string.
Questions:
Is it normal for all 3 components to re-render many many times while the user is entering the search phrase?
Are there ways to pass data from SearchBarView to SearchScreen and then to SearchResultView without causing all 3 components to re-render?
How to address the issue that the searchPhrase always ended up in empty string?
It appears SearchBarView is being unmounted then mounted when SearchScreen re-re-renders. that caused the useState to take the initial empty value which makes the searchPhrase always ended up in empty string. Does re-render always unmount and mount again? How to prevent it to re-mounted?
SearchScreen.tsx
const SearchScreen: React.FC = () => {
const [searchResult, setSearchResult] = useState<string[]>([]);
const onSearchPhraseUpdate = (text: string) => {
setSearchResult('some','search','result','strings');
};
return (
<SafeAreaView>
<SearchBarView
onSearchPhraseUpdate={onSearchPhraseUpdate}
/>
<SearchResultView
results={searchResult}
/>
</SafeAreaView>
);
};
export default SearchScreen;
SearchBarView.tsx
interface IProps {
readonly onSearchPhraseUpdate: (text: string) => void;
}
const SearchBarView: React.FC<IProps> = (props) => {
const { onBackButtonPress, onSearchPhraseUpdate } = props;
const [searchPhrase, setSearchPhrase] = useState('');
const _searchPhrase = _debounce((text: string)=>{
setSearchPhrase(text);
onSearchPhraseUpdate(text);
}, 500);
console.log("SearchBarView searchPhrase: ", searchPhrase);
return (
<SearchTextInput
style={{flex: 1}}
onChangeText={_searchPhrase}
keyboardType='default'
/>
);
};
export default SearchBarView;
SearchResultView.tsx
interface IProps {
readonly results: string[];
}
const SearchResultView: React.FC<IProps> = (props) => {
const { results } = props;
return (
<MyListView results={results}/>
);
};
export default SearchResultView;