从搜索输入中删除查询仍在页面上显示结果

s1ag04yj  于 2021-09-13  发布在  Java
关注(0)|答案(2)|浏览(334)

我有一个主页,可以在其中显示搜索结果 searchContext . 这是我的 home page 代码。

import { useSearch } from "./SearchContext";

const Home = () => {
  const { isLoading, search, searchResult } = useSearch();
  const startIndex = Math.floor(Math.random() * searchResult.length - 5);

  return (
    <>
      <h3>Home page</h3>
      {isLoading ? (
        <h1>LOADING...</h1>
      ) : (
        <div>
          <div>Search value: {search}</div>
          {searchResult.slice(startIndex, startIndex + 5).map((el) => (
            <li key={el.id}>{el.title}</li>
          ))}
        </div>
      )}
    </>
  );
};

export default Home;

这是我的 searchContext .

import { createContext, useEffect, useContext, useState } from "react";

export const SearchContext = createContext({
  isLoading: false,
  search: "",
  searchResult: [],
  setSearch: () => {}
});

export const useSearch = () => useContext(SearchContext);

const SearchProvider = ({ children }) => {
  const [search, setSearch] = useState("");
  const [items, setItems] = useState([]);
  const [isLoading, setIsLoading] = useState(false);

  useEffect(() => {
    const searchNews = async () => {
      console.log(search);
      setIsLoading(true);
      const news = await fetchNews(search, 15, 1);
      setItems(news);
      setIsLoading(false);
    };

    const fetchNews = async (section, pageSize, page) => {
      // const url = `${baseUrl}${section}?page-size=${pageSize}&page=${page}&api-key=${apiKey}`;
      const url = "https://jsonplaceholder.typicode.com/posts";
      const news = await fetch(url);
      return await news.json();
    };
    if (search.length > 0) { // I added this condition so that searchNews is not called when search is empty.
      searchNews();
    } // Here I can add an else statement and call `setItems([])` to set empty array to items but it does not work either.
  }, [search]);

  return (
    <SearchContext.Provider
      value={{
        isLoading,
        search,
        searchResult: items,
        setSearch: (e) => setSearch(e.target.value)
      }}
    >
      {children}
    </SearchContext.Provider>
  );
};

export default SearchProvider;

此上下文正在继续调用 searchNews 当我输入文本到 input field . 这对于搜索和显示结果非常有效。但是当我离开的时候 search string 从…起 input field 然后,我不希望它显示或检索api调用的任何更多结果。现在,如果我慢慢地移除 search string 从…起 input field . 但是当我离开的时候 search string 越来越快 items 仍然有结果,并在屏幕上显示这些结果 home page . 我不要这个。我想当 search input 如果是空的,那么我不想显示任何 search result 在…上 home page 或任何页面。
为了解决这个问题,我在中添加了一个if条件 searchContext 检查 search 不是空的,这意味着 input field 不是空的,然后打电话 searchNews 方法并从api加载结果,但如果该结果为空,则不调用 searchNews 不应该显示的内容 search result 在任何页面上。
这是带有搜索输入字段的search.js页面。

import { useSearch } from "./SearchContext";

const Search = () => {
  const { setSearch } = useSearch();

  return (
    <>
      <input
        type="text"
        name="search"
        placeholder="Enter search term"
        onChange={setSearch}
      />
    </>
  );
};

export default Search;

当我越来越快地删除搜索字符串时,如何解决此问题?
下面是解决此问题的代码沙盒。
https://codesandbox.io/s/replace-search-current-page-contents-with-search-contents-forked-x4l0o?file=/src/searchcontext.js

e5nqia27

e5nqia271#

我认为问题在于您正在处理的事件,onchange事件非常适合select元素,而input元素需要oninput事件。尝试使用oninput事件更改onchange事件

6tr1vspr

6tr1vspr2#

当我们创建任何自动完成组件时,我们需要考虑用户的输入速度,以及每字母搜索是否适合这种情况(很可能不是)。
因此,我们可以学习在等待输入时,在执行提取之前使用debounce或settimeout来创建一个轻微的延迟。
在本例中,创建一个全局变量 timer 它位于组件外部,因此不会在每次渲染时调用/重置它。

let timer; //outside component

const mycomponent = () => {

.....

  useEffect(() => {
    const searchNews = async () => {

      setIsLoading(true);
      clearTimeout(timer) //clear timer on every call
      timer = setTimeout(() => { //recreate a timer to call the fetch in 100ms
          const news = await fetchNews(search.length ? search : "news", 15, 1);
          setItems(news);
          setIsLoading(false); //need to add try /catch 
      }, 100) //<--- call the function in 100 ms

    };
if (search.length > 0) {
  searchNews();
} else {
  setItems([]);
}
    .............
  }, [search]); 
}

我们将创建计时器,并在每个输入上使用cleartimeout(计时器)重置计时器。一旦用户暂停键入,您将执行提取。
ps:可以增加100毫秒的延迟以提高性能。我使用的是200ms,它在我的后端运行良好,在不到100ms的时间内返回结果。

相关问题