Home > front end >  What is the proper way to pass data between child components?
What is the proper way to pass data between child components?

Time:12-12

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;

CodePudding user response:

Is it normal for all 3 components to re-render many many times while the user is entering the search phrase?

Yes, since all 3 components gets an update:

  1. SearchBarView: get direct input
  2. SearchScreen: notified of the new text change by SearchBarView
  3. SearchResultView: get new update result by SearchScreen

So all three components should re-render.

Are there ways to pass data from SearchBarView to SearchScreen and then to SearchResultView without causing all 3 components to re-render?

No. Ff the update didn't happen, then the component will not be aware of the updates on the text the user entered.

How to address the issue that the searchPhrase always ended up in empty string?

This is weird since useState takes the parameter value for one time only. The only case that useState could be the reason would be when the component gets unmounted then mounted again. but the problem may be from elsewhere.

It will be very useful If you can provide a working example on codeSandbox. but as a hint that may solve the issue: wrap every callback props with useCallback hook. that will make sure that no false updates will cause undesired re-render for SearchResultView and SearchBarView

CodePudding user response:

we can look at the problem from another prospective so we reduce the several renders to a single render whenever the typing is finished.

this has been discussed here :

How to start search only when user stops typing?

  • Related