简体   繁体   English

React 中的搜索和分页存在错误

[英]There's a bug with Search and Pagination in React

I'm building my site in React and I have created pagination and search.我正在用 React 构建我的网站,并创建了分页和搜索。 When I search for something on the site, it only works when after that I go to another page.当我在网站上搜索某些内容时,它仅在我 go 到另一个页面时才有效。 I think this is due to the fact that Softwares and Pagination are in the same component.我认为这是因为软件和分页在同一个组件中。

Then I tried lifting-state-up, but I got an error: React Minified Error # 31.然后我尝试提升状态,但出现错误:React Minified Error # 31。

Here's Pagination component:这是分页组件:

const Paginator = ({
    total, // Total records
    startPage = 1,
    totalPages = null,
    onMovePage = null,
  }) => {

  ...

  return (
    <>
      <section id={styles.paginator}>

        <Header/>

        ...

        {range(1, totalPages+1).map(p => (
          <PagItem key={p} handleClick={ () => {setCurrentPage(p); onMovePage && onMovePage({currentPage: p})} } title={p} name={p} />
        ))}

        ...
      </section>
    </>
  );
};

Here's Softwares component:这是软件组件:

const Softwares = ({ search }) => {

  const [softwares, setSoftwares] = useState([]);
  const [total, setTotal] = useState(null);
  const [totalPages, setTotalPages] = useState(null);
  const [valid, setValid] = useState(false);

  const fetchData = async ({ currentPage }) => {

    const SEARCH = search ? `?search=${search}` : '';
    const CURRENT_PAGE = currentPage && SEARCH === '' ? `?page=${currentPage}` : '';

    const response = await fetch(`http://127.0.0.1:8000/api/software/${CURRENT_PAGE}${SEARCH}`);

    const data = await response.json();

    setSoftwares(data.results);
    setTotal(data.count);
    setTotalPages(data.total_pages);
    setValid(true);

  }

  useEffect(() => {
    fetchData({ currentPage: 1 });
  }, []);

  return (
    <>
    {
      valid &&
      <section className={styles.softwares}>
        <Header header={"new softwares"} />
        {softwares.map(s => (
          <Article key={s.id} pathname={s.id} title={s.title} image={s.image} pubdate={s.pub_date} icon={s.category.parent.img} categoryID={s.category.id} categoryName={s.category.name} dCount={s.counter} content={s.content} />
        ))}
        <Paginator totalPages={totalPages} total={total} onMovePage={fetchData} />
      </section>
    }
    </>
  );
};

SearchForm in Header component: Header 组件中的搜索表单:

const Header = ({ handleChange, handleClick }) => {

  return (
    ...

        <SearchForm handleChange={handleChange} handleClick={handleClick} />

    ...
  );
};

const SearchForm = ({ style, handleChange, handleClick }) => {

  return (
    <div style={style}>
      <form>
        <input
          type="text"
          onChange={handleChange}
        />
        <SearchButton onClick={handleClick} />
        <small>ENTER</small>
      </form>
    </div>
  );
};

const SearchButton = ({onClick }) => {
  return (
    <button type="button" onClick={onClick}>
      <FontAwesomeIcon icon={faSearch} />
    </button>
  );
};

And part of Search in App component:以及在 App 组件中搜索的一部分:

const App = () => {

    ...
    
    // Search
  const [search, setSearch] = useState('');
  const [shouldFetch, setShouldFetch] = useState(false);

  const handleChange = (e) => {
    setSearch(e.target.value);
  }

  useEffect(() => {

    if (shouldFetch) {

      (async () => {

        const response = await fetch(`http://127.0.0.1:8000/api/software/?search=${search}`);

        const data = await response.json();

        setShouldFetch(false);

      })()

    }

  }, [shouldFetch]);

  const handleClick = () => setShouldFetch(true);

    return (
        <div className="App">

      <Header handleChange={handleChange} handleClick={handleClick} />

      ...

      <Switch>
        <Route path="/" exact render={props => <Softwares {...props} search={search} />} />
      </Switch>

            {/* Actually I'd like to use Paginator here, but it 
                    throws the error: React Minified Error # 31 */}

            ...

    </div>
    );

}

So, how can this be done?那么,如何做到这一点呢?

The problem is your useEffect dependencies (or lack thereof).问题是您的useEffect依赖项(或缺少依赖项)。

Here's the relevant section of the code:这是代码的相关部分:

const Softwares = ({ search }) => {

  const [softwares, setSoftwares] = useState([]);
  const [total, setTotal] = useState(null);
  const [totalPages, setTotalPages] = useState(null);
  const [valid, setValid] = useState(false);

  const fetchData = async ({ currentPage }) => {

    const SEARCH = search ? `?search=${search}` : '';
    const CURRENT_PAGE = currentPage && SEARCH === '' ? `?page=${currentPage}` : '';

    const response = await fetch(`http://127.0.0.1:8000/api/software/${CURRENT_PAGE}${SEARCH}`);

    const data = await response.json();

    setSoftwares(data.results);
    setTotal(data.count);
    setTotalPages(data.total_pages);
    setValid(true);

  }

  useEffect(() => {
    fetchData({ currentPage: 1 });
  }, []);

The empty dependency array means that you are running the effect that calls fetchData one time when the component mounts.空依赖数组意味着您正在运行在组件挂载时调用fetchData一次的效果。 Clicks in the Pagination component will call the fetchData function directly.Pagination组件中点击会直接调用fetchData function。 Changes to search do not cause fetchData to re-run .search的更改不会导致fetchData重新运行 The data depends on the search so search should be a dependency.数据取决于search ,因此search应该是依赖项。

The fetchData function is fine in this component. fetchData function 在这个组件中很好。 The state that I would recommend lifting up is to lift the currentPage up from Pagination into Softwares .我建议提升的 state 是将currentPagePagination提升到Softwares The onMovePage callback can just update the currentPage state. onMovePage回调可以只更新currentPage state。 That way you can call fetchData only through your effect and run the effect whenever either search or currentPage changes.这样,您可以仅通过效果调用fetchData并在searchcurrentPage更改时运行效果。

const Softwares = ({ search }) => {

  const [softwares, setSoftwares] = useState([]);
  const [total, setTotal] = useState(null);
  const [totalPages, setTotalPages] = useState(null);
  const [valid, setValid] = useState(false);
  const [currentPage, setCurrentPage] = useState(1);

  useEffect(() => {
    // defining the function inside of the useEffect
    // lets eslint exhaustive dependency checks work their magic
    const fetchData = async () => {

      const SEARCH = search ? `?search=${search}` : '';
      const CURRENT_PAGE = currentPage && SEARCH === '' ? `?page=${currentPage}` : '';
  
      const response = await fetch(`http://127.0.0.1:8000/api/software/${CURRENT_PAGE}${SEARCH}`);
  
      const data = await response.json();
  
      setSoftwares(data.results);
      setTotal(data.count);
      setTotalPages(data.total_pages);
      setValid(true);
    }
  
    // need to define and call in separate steps when using async functions
    fetchData();

  }, [currentPage, search]);

  return (
    ...
        <Paginator page={currentPage} totalPages={totalPages} total={total} onMovePage={setCurrentPage} />
    ...
  );
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM