Lagging input field in React (speed optimization)

I would like advice on how to improve the overall speed and prevent lagging input, you will notice the input box lags especially when pressing backspace:

Assume the api at jsonplaceholder can change, so I dont want to use any named properties and keep it dynamic as possible.
I thought of extracting components or using memoization hooks but I wasnt sure… It is perhaps using too much DFS and BFS maybe there is a way to restructure the data so Im not doing this every time.

I also plan to turn the text into editable input fields

relevant files:

//entries

import useFetchPromiseAll from "../hooks/useFetchPromiseAll";
import { useState } from "react";

function highlight(value, highlight) {
  const parts = value.toString().split(new RegExp(`(${highlight})`, "gi"));
  return parts.map((part, index) => (
    <span key={index}>
      {part === highlight ? (
        <b style={{ backgroundColor: "#ADD8E6" }}>{part}</b>
      ) : (
        part
      )}
    </span>
  ));
}

function Entry({ entry, level, input }) {
  return (
    <div>
      {Object.values(entry).map((x) => {
        if (typeof x !== "object") {
          return (
            <div style={{ marginLeft: `${level * 10}px` }}>
              {highlight(x, input)}
            </div>
          );
        }
        return (
          <Entry level={level + 1} entry={Object.values(x)} input={input} />
        );
      })}
    </div>
  );
}

const params = ["users", "posts"];

function Entries() {
  const { users, posts } = useFetchPromiseAll(params);

  const entries = users?.map((user) => {
    user[params[1]] = posts.filter((post) => post.userId === user.id);
    return user;
  });

  const [input, setInput] = useState("");

  const searchEntry = (entry) => {
    const queue = [...Object.values(entry)];
    while (queue.length > 0) {
      const element = queue.shift();
      if (typeof element === "object") {
        queue.push(...Object.values(element));
      } else {
        if (element.toString().toLowerCase().includes(input.toLowerCase())) {
          return true;
        }
      }
    }
  };

  const filtered = entries?.filter((entry) => {
    return searchEntry(entry);
  });

  return (
    <>
      {entries && (
        <input value={input} onChange={(e) => setInput(e.target.value)} />
      )}
      {filtered?.map((entry) => (
        <Entry key={entry.id} entry={entry} level={0} input={input} />
      ))}
    </>
  );
}

export default Entries;

//useFetchPromiseAll


import { useEffect, useState } from "react";
import getFetchData from "../utils/getFetchData";
function useFetchPromiseAll(params) {
  const [data, setData] = useState([]);
  useEffect(() => {
    const Data = getFetchData(params);
    Promise.all([...Data]).then((res) => {
      const response = {};
      for (let i = 0; i < res.length; i++) {
        response[params[i]] = res[i];
      }
      setData(response);
    });
  }, [params]);
  return data;
}

export default useFetchPromiseAll;

//GetFetchData utility

import { useEffect, useState } from "react";
import getFetchData from "../utils/getFetchData";
function useFetchPromiseAll(params) {
  const [data, setData] = useState([]);
  useEffect(() => {
    const Data = getFetchData(params);
    Promise.all([...Data]).then((res) => {
      const response = {};
      for (let i = 0; i < res.length; i++) {
        response[params[i]] = res[i];
      }
      setData(response);
    });
  }, [params]);
  return data;
}

export default useFetchPromiseAll;

Edit: Ive given some self thought, here is my analysis:

  1. if I do some of the work to reorganize the structuring of the data in the custom effect (outside of the main component) it will help (like maybe flattening the data?) . running Entry() (the DFS) on each render is too expensive, (the way that function is currently built… )
  2. if I fix the keys complaint and also possibl use a debouncing technique on input change It will fix the lagging.
  3. I also was wondering if this is a use case for the memo hooks of react or if those will really do much for me at all…
  4. in any case I still need to do the Breadth first search on input change its unavoidable as im searching for every occuarance.
  5. I didnt really want to do any processing work inside of that custom hook so I think an HOC is appropriate in this case?

Let me know your thoughts and if there is somethign I missed.

1 Like

Do you have this running on a repl/netlify or something so we can try it out and mess around?

Maybe I don’t understand what you’re doing, but correct me if I’m wrong: you want to highlight all instances of a certain value in a text box while type?

Couldn’t you just:

  1. set a handleInput function to move the value of the textbox into state
  2. use a regex to find all instances of the selected values
  3. insert your highlight code into the string at those instances

Seems much faster than what you’re doing above? Sorry if I’m missing what you’re trying to do. I think I need to see the app running to understand what you’re going for.

hi its just a practice project…

display a list of all users and posts returned by api, filter the list of users by search value and highlight all instances of search value

get all the data reguardless of if the api will change at some point /things may be added in the future at any depth. do not stringify and output all the data or output each entire user as a string into a large text box. however, I will turn each value into its own editable text box. I do not want to use any named properties or strings in the code. so no property.someName etc… it must be dynamic

I will add some other features as well but thats the gist. you can think of this somewhat like a fileSystem in vs code.


git clone https://github.com/KravMaguy/dynamic-highlight
cd dynamic-highlight
npm i
npm start

that is being done

that is being done

that is being done

I do think a combination of extracting the depth first search and perhaps flattening the object outside the component as well as using debounce and wrapping component in HOC is what it needs… see my comments in original post.

@Salathor ive fixed the lagging inputs, the main thing was memoization hooks, extracting components, the debouncer, as well as returning the value from the highlight if no input:

https://github.com/KravMaguy/dynamic-highlight/blob/master/src/components/Highlight.jsx#L3

although the performance is now greatly improved, one other thing id like to fix is that this function is still expensive :

Let me know what you think…

also if you dont want to clone a project from github you can just use codesandbox so in this case:

githubbox.com/kravmaguy/dynamic-highlight

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.