reactjs 只需点击两次即可更新状态

wd2eg0qa  于 2023-03-01  发布在  React
关注(0)|答案(2)|浏览(141)

尽管使用回调函数更新状态,但filteredBooks状态仅在第二次点击后更新。

import { useRef, useEffect, useState } from "react";
import "./App.css";
import Card from "./UI/Card";

function App() {
  const [books, setBooks] = useState([]);
  const [filteredBooks, setFilteredBooks] = useState([]);
  const [yearRange, setYearRange] = useState([]);
  const filterBksByYearRange = () => {
    const filtered = books.filter(
      (book) => book.year >= yearRange[0] && book.year <= yearRange[1]
    );
    setFilteredBooks(() => filtered);
  };
  const handleYrRange = (e) => {
    e.preventDefault();
    const yearStart = parseInt(e.target[0].value);
    const yearEnd = parseInt(e.target[1].value);
    console.log(yearStart, yearEnd);
    setYearRange(() => [yearStart, yearEnd]);
    // SOLVE: books complete list only at initial fetch. if multiple filters applied, will not reflect accurate filter
    filterBksByYearRange();
  };
  useEffect(() => {
    const url = "/books";

    const fetchData = async () => {
      try {
        const response = await fetch(url);
        const json = await response.json();
        console.log(json);
        setBooks((prev) =>
          [prev, ...json.body].map((book) => {
            return {
              title: book.title,
              author: book.author,
              year: parseInt(book.year),
              isbn: parseInt(book.isbn),
            };
          })
        );
      } catch (error) {
        console.log("error", error);
      }
    };

    fetchData();
  }, []);

  return (
    <div className="App">
      <h1>ServicePros Coding Challenge</h1>
      <form onSubmit={handleYrRange}>
        <label>
          Start Year:
          <input type="text" name="yearStart" placeholder="" />
        </label>
        <label>
          Start End:
          <input type="text" name="yearEnd" placeholder="" />
        </label>
        <button type="submit">Filter by Year</button>
      </form>
      <ul>
        {filteredBooks.length > 0 ? (
          filteredBooks.map((book) => (
            <Card key={Math.random()}>
              <li>
                <div>Title: {book.title}</div>
                <div>Author: {book.author}</div>
                <div>Year: {book.year}</div>
                <div>ISBN: {book.isbn}</div>
              </li>
            </Card>
          ))
        ) : (
          <p>No Books Filtered</p>
        )}
      </ul>
    </div>
  );
}

export default App;
oogrdqng

oogrdqng1#

因为filterBksByYearRange();基于yearRange状态工作,并且后者不会在更新时立即更改,而是在下一次渲染时更改,因此:

setYearRange(() => [yearStart, yearEnd]);
filterBksByYearRange(); //this will not work with the new data of `yearRange`

一种替代方法是更新您的filterBksByYearRange()函数:

const filterBksByYearRange = (yearStart, yearEnd) => {
  const filtered = books.filter(
    (book) => book.year >= yearStart && book.year <= yearEnd
  );
  setFilteredBooks(() => filtered);
};

并这样使用它:

setYearRange(() => [yearStart, yearEnd]);
// SOLVE: books complete list only at initial fetch. if multiple filters applied, will not reflect accurate filter
filterBksByYearRange(yearStart, yearEnd);
g52tjvyc

g52tjvyc2#

第一次单击时filteredBooks状态没有更新的原因是setYearRangefilterBkByYearRange函数是异步的,这意味着filteredBooks状态是用yearRange的先前值而不是更新后的值设置的。
要解决这个问题,你可以把filterBkByYearRange函数移到一个依赖yearRange的useEffect钩子中,如下所示:

useEffect(() => {
  const filterBksByYearRange = () => {
    const filtered = books.filter(
      (book) => book.year >= yearRange[0] && book.year <= yearRange[1]
    );
    setFilteredBooks(filtered);
  };
  filterBksByYearRange();
}, [books, yearRange]);

相关问题