Home > Mobile >  run useState on unmounted component
run useState on unmounted component

Time:11-11

I have a state which is used to render some components conditionally, I have the following structure:


const SearchScreen = () => {
  const [isSearchBarFocused, setIsSearchBarFocused] = React.useState(false);

  return (
      <>
         <SearchBar onFocus={setIsSearchBarFocused} />
         {isSearchBarFocuse ? <SearchSuggestionList isSearchBarFocused={isSearchBarFocused} setIsSearchBarFocused={setIsSearchBarFocused} /> : null}
      </>
  )

}

As you can see in the code above, the state seter is shared by both components, when the <SearchBar /> is focused the state changes to true and when an option is selected from the <SearchSuggestionList /> the state change to false. The problem with this approach is that I need to run some API calls and other inner state updates in <SearchSuggestionList /> component but this is unmounted due to the conditional rendering then some processes are not reached to be carried out.

then how would I execute code that is inside a component that can be unmounted?

CodePudding user response:

At SearchScreencomponent: You need to add event onBlur for search-input, it will auto trigger when click outside search-input. And add two events onChange and value to get the enter value from search-input. Finally, don't check isSearchBarFocused variable outside SearchSuggestionList component.

export default function SearchScreen() {
  const [isSearchBarFocused, setIsSearchBarFocused] = useState(false);
  const [searchBarValue, setSearchBarValue] = useState("");

  const handleChangeSearchValue = (e) => {
    setSearchBarValue(e.target.value);
  };

  const handleBlurSearch = () => {
    setIsSearchBarFocused(false);
  };

  const handleFocusSearch = () => {
    setIsSearchBarFocused(true);
  };

  return (
    <div className="App">
      <div className="searchbar-wrapper">
        <input
          className="search-input"
          type="text"
          onFocus={handleFocusSearch}
          onChange={handleChangeSearchValue}
          value={searchBarValue}
          onBlur={handleBlurSearch}
        />
        <SearchSuggestionList
          isSearchBarFocused={isSearchBarFocused}
          searchBarValue={searchBarValue}
        />
      </div>
    </div>
  );
}

At SearchSuggestionList component: You need to create isSearchBarFocused and searchBarValue for Props. The display atrribute will change none or block depend on isSearchBarFocused

.search-list {
  display: none;
}

.search-list.active {
  display: block;
}

and if searchBarValue changes value, useEffect will trigger and re-call API

import { useEffect, useState } from "react";

const MOCKUP_DATA = [
  { id: 1, value: "Clothes" },
  { id: 2, value: "Dress" },
  { id: 3, value: "T-shirt" }
];

const SearchSuggestionList = ({ searchBarValue, isSearchBarFocused }) => {
  const [suggestionData, setSuggestionData] = useState([]);
  useEffect(() => {
    // useEffect will call API first time and re-call every time `searchBarValue` changed value.
    console.log("re-call api");
    setSuggestionData(MOCKUP_DATA);
  }, [searchBarValue]);

  const handleClick = (value) => {
    console.log(value);
  };

  return (
    <ul className={`search-list ${isSearchBarFocused ? "active" : ""}`}>
      {suggestionData.map((item) => (
        <li key={item.id} onm ouseDown={() => handleClick(item.value)}>
          {item.value}
        </li>
      ))}
    </ul>
  );
};

export default SearchSuggestionList;

Warning: If you use onClick to replace onMouseDown, it will not work. Because onBlur event of search-input will trigger before onClick event of the items in SearchSuggestionList


You can demo it at this link: https://codesandbox.io/s/inspiring-cori-m1bsv0?file=/src/App.jsx

CodePudding user response:

Please try to use && instead of ternary operator(?) like this:

const SearchScreen = () => {
  const [isSearchBarFocused, setIsSearchBarFocused] = React.useState(false);

  return (
      <>
         <SearchBar onFocus={setIsSearchBarFocused} />
         {isSearchBarFocused && <SearchSuggestionList isSearchBarFocused={isSearchBarFocused} setIsSearchBarFocused={setIsSearchBarFocused} />}
      </>
  )

}
  • Related