Home > database >  React race condition issue in useEffect
React race condition issue in useEffect

Time:12-18

I am just trying to figure out a weird issue in my React project. So I am executing some code in my useEffect. As you can see, I am trying to grab the currentObj from an array of objects based on searchTerm. However, there seems to be a race condition in getting the value searchTerm. The toggleFilter and setAvailabilities functions below are throwing an error saying that the id is not defined. And the page crashes.

useEffect(() => {
    const search = window.location.search;
    const params = new URLSearchParams(search);
    let param = "";

    if (search.includes("neighborhood")) {
      param = params.get("neighborhood");
      const searchTerm = search.toLowerCase();
      if (searchTerm) {
        const currentObj = searchTerm && locations.find(item => item.linktitle.toLowerCase().includes(searchTerm));
        console.log(searchTerm, currentObj);

      toggleFilter(currentObj.id);
      setAvailabilitiesFilter([currentObj.id]);
      } 
    }

    return () => resetAllFilters();
  }, []);

However, if I hardcode a value into it, it actually renders ok and the page does not crash.

const currentObj = searchTerm && locations.find(item => item.linktitle.toLowerCase().includes('manhattan'));

That is why I am thinking it is a race condition in getting the id. Also when I look at the console log from hardcoded searchTerm, it is showing the searchTerm property. But I do not want to hardcode it.

But of course, I don't want to hardcode the value as I expect to dynamically render the searchTerm

Is there any way I can in the useEffect wait until searchTerm is defined before running that .find method? I also tried adding the searchTerm in the dependency array but that doesn't seem right as it is not giving suggestions there and seems not to be scoped there.

Any help appreciated. Thanks!

CodePudding user response:

Have you tried this?

const search = window.location.search;
search.substring(1) // this will ignore "?" in the result which could be causing the issue on finding the correct object

Have you tried printing the value of search here?

console.log(search);

if yes, what is it that you see?

Also, you don't need to repeat yourself by doing this:

  if (searchTerm) {
    const currentObj = searchTerm && locations.find(item => item.linktitle.toLowerCase().includes(searchTerm));
    ...
  } 

You are already checking if searchTerm has been defined inside your if statement so you can simply do this:

if (searchTerm) {
    const currentObj = locations.find(item => item.linktitle.toLowerCase().includes(searchTerm));
    ...

Finally, to avoid any other errors before using your functions you can check if you actually have an id or not like this:

if(currentObj.id) {
  toggleFilter(currentObj.id);
  setAvailabilitiesFilter([currentObj.id]);
}

Hope that helps!

CodePudding user response:

It seems the issue is that you are using the entire query search string in the .find predicate callback.

useEffect(() => {
  const search = window.location.search; // <-- entire search string

  const params = new URLSearchParams(search);
  let param = "";

  if (search.includes("neighborhood")) {
    param = params.get("neighborhood");

    const searchTerm = search.toLowerCase(); // <-- still entire search string

    if (searchTerm) {
      const currentObj = searchTerm && locations.find(
        item => item.linktitle.toLowerCase()
          .includes(searchTerm) // <-- still entire search string
      );

      console.log(searchTerm, currentObj);

      toggleFilter(currentObj.id); // <-- throws error if undefined currentObj
      setAvailabilitiesFilter([currentObj.id]);
    } 
  }

  return () => resetAllFilters();
}, []);

Array.prototype.find returns undefined when no array element is found using the predicate function, and the code does not properly check for a truthy result value prior to attempting to access into it for nested properties like id.

I'm going to guess at this point that you are wanting to search the link titles for a matching neighborhood value, which is param in your code.

useEffect(() => {
  const search = window.location.search;
  const params = new URLSearchParams(search);

  // get the neighborhood querystring param
  const neighborhood = params.get("neighborhood");

  // check if it exists
  if (neighborhood) {
    // it does, search the locations array
    const currentObj = locations.find(
      ({ linktitle }) => linktitle.toLowerCase().includes(neighborhood.toLowerCase())
    );

    // check if result was found
    if (currentObj) {
      // it was found, access into object to get id property
      toggleFilter(currentObj.id);
      setAvailabilitiesFilter([currentObj.id]);
    }
  }

  return () => resetAllFilters();
}, []);
  • Related