0

我正在尝试将此类基于组件的组件转换为函数组件。由于某种原因,handleFormSubmit函数没有读取Query ( setQ ) 。当我将 setQ 中的参数设为对象时,输入表单的值变为 [object, Object]。我究竟做错了什么?

类组件

import React, { Component } from "react";
import Jumbotron from "../components/Jumbotron";
import Card from "../components/Card";
import Form from "../components/Form";
import Book from "../components/Book";
import Footer from "../components/Footer";
import API from "../utils/API";
import { Col, Row, Container } from "../components/Grid";
import { List } from "../components/List";

class Home extends Component {
  state = {
    books: [],
    q: "",
    message: "Search For A Book To Begin!"
  };

  handleInputChange = event => {
    const { name, value } = event.target;
    this.setState({
      [name]: value
    });
  };

  getBooks = () => {
    API.getBooks(this.state.q)
      .then(res =>
        this.setState({
          books: res.data
        })
      )
      .catch(() =>
        this.setState({
          books: [],
          message: "No New Books Found, Try a Different Query"
        })
      );
  };

  handleFormSubmit = event => {
    event.preventDefault();
    this.getBooks();
  };

  handleBookSave = id => {
    const book = this.state.books.find(book => book.id === id);

    API.saveBook({
      googleId: book.id,
      title: book.volumeInfo.title,
      subtitle: book.volumeInfo.subtitle,
      link: book.volumeInfo.infoLink,
      authors: book.volumeInfo.authors,
      description: book.volumeInfo.description,
      image: book.volumeInfo.imageLinks.thumbnail
    }).then(() => this.getBooks());
  };

  render() {
    return (
      <Container>
        <Row>
          <Col size="md-12">
            <Jumbotron>
              <h1 className="text-center">
                <strong>(React) Google Books Search</strong>
              </h1>
              <h2 className="text-center">Search for and Save Books of Interest.</h2>
            </Jumbotron>
          </Col>
          <Col size="md-12">
            <Card title="Book Search" icon="far fa-book">
              <Form
                handleInputChange={this.handleInputChange}
                handleFormSubmit={this.handleFormSubmit}
                q={this.state.q}
              />
            </Card>
          </Col>
        </Row>
        <Row>
          <Col size="md-12">
            <Card title="Results">
              {this.state.books.length ? (
                <List>
                  {this.state.books.map(book => (
                    <Book
                      key={book.id}
                      title={book.volumeInfo.title}
                      subtitle={book.volumeInfo.subtitle}
                      link={book.volumeInfo.infoLink}
                      authors={book.volumeInfo.authors.join(", ")}
                      description={book.volumeInfo.description}
                      image={book.volumeInfo.imageLinks.thumbnail}
                      Button={() => (
                        <button
                          onClick={() => this.handleBookSave(book.id)}
                          className="btn btn-primary ml-2"
                        >
                          Save
                        </button>
                      )}
                    />
                  ))}
                </List>
              ) : (
                <h2 className="text-center">{this.state.message}</h2>
              )}
            </Card>
          </Col>
        </Row>
        <Footer />
      </Container>
    );
  }
}

export default Home;

功能转换

import React from "react";
// import Jumbotron from "react-bootstrap/Jumbotron";
import Row from "react-bootstrap/Row";
import Card from "../components/Card";
import Form from "../components/Form";
import Col from "react-bootstrap/Col";
import Container from "react-bootstrap/Container";
import Jumbotron from "react-bootstrap/Jumbotron";
import { useState } from "react";
import API from "../utils/API";
import Book from "../components/Book";
import Button from "react-bootstrap/Button";
import { List } from "../components/List";
import Footer from "../components/Footer";
import "./style.css";

export default function Home() {
  let [books, setBooks] = useState([]);
  let [q, setQ] = useState("");
  let [message, setMessage] = useState("Search For A Book to Begin");

  const handleInputChange = (event) => {
    let { name, value } = event.target;
    setQ(([name] = value));
  };

  let getBooks = () => {
    API.getBooks(q)
      .then((res) => setBooks(res.data))
      .catch(() => setBooks([]));
    setMessage("No New Books Found, Try a Different Query");
  };

  const handleFormSubmit = (event) => {
    event.preventDefault();
    getBooks();
  };

  let handleBookSave = (id) => {
    const book = books.find((book) => book.id === id);

    API.saveBook({
      googleId: book.id,
      title: book.volumeInfo.title,
      subtitle: book.volumeInfo.subtitle,
      link: book.volumeInfo.infoLink,
      authors: book.volumeInfo.authors,
      description: book.volumeInfo.description,
      image: book.volumeInfo.imageLinks.thumbnail,
    }).then(() => getBooks());
  };

  return (
    <div>
      <Container>
        <Row>
          <Col md={12}>
            <Jumbotron className="rounded-3 mt-4">
              <h1 className="text-center ">
                <strong>(React) Google Books Search</strong>
              </h1>
              <h2 className="text-center">
                Search for and Save Books of Interest.
              </h2>
            </Jumbotron>
          </Col>
          <Col md={12}>
            <Card title="Book Search" icon=" fa-book">
              <Form
                handleInputChange={handleInputChange}
                handleFormSubmit={handleFormSubmit}
                q={q}
              />
            </Card>
          </Col>
        </Row>
        <Row>
          <Col md={12}>
            <Card title="Results">
              {books.length ? (
                <List>
                  {books.map((book) => (
                    <Book
                      key={book.id}
                      title={book.volumeInfo.title}
                      subtitle={book.volumeInfo.subtitle}
                      link={book.volumeInfo.infolink}
                      authors={book.volumeInfo.authors.join(", ")}
                      description={book.volumeInfo.description}
                      image={book.volumeInfo.imageLinks.thumbnail}
                      Btn={() => (
                        <Button
                          onClick={() => handleBookSave(book.id)}
                          variant="primary"
                          className="ml-2"
                        >
                          Save
                        </Button>
                      )}
                    />
                  ))}
                </List>
              ) : (
                <h2 className="text-center">{message}</h2>
              )}
            </Card>
          </Col>
        </Row>
        <Footer />
      </Container>
    </div>
  );
}

4

1 回答 1

1

我不确定你到底想要什么,但我看到了问题。

首先让我们看这里:

  state = {
    books: [],
    q: "",
    message: "Search For A Book To Begin!"
  };

  handleInputChange = event => {
    const { name, value } = event.target;
    this.setState({
      [name]: value
    });
  };

在类组件中,state是一个具有属性的对象。您正在利用这一事实来允许使用动态访问各个状态name,然后将其设置为value.


现在让我们看一下功能组件:

  let [books, setBooks] = useState([]);
  let [q, setQ] = useState("");
  let [message, setMessage] = useState("Search For A Book to Begin");

  const handleInputChange = (event) => {
    let { name, value } = event.target;
    setQ(([name] = value));
  };

请注意,您不再拥有单个状态对象。你有三个完全独立的状态。这个handleInputChange函数只设置其中一个,q.

而且[name] = value特别奇怪。实际上所做的是将字符串的第一个字符分配给value变量name,该变量永远不会再次使用或读取。这当然不是你想要的。

为了做我认为你想要的事情,你必须setMyStateHere()明确地调用每个 setter。

所以我想你想要这个:

  const handleInputChange = (event) => {
    let { name, value } = event.target;
    if (name === 'q') {
      setQ(value)
    } else if (name === 'message') {
      setMessage(value)
    } else {
      throw new Error(`Unhandled input name: ${name}`) // or something
    }
  };

在这里,您检查name以确定要设置的状态,然后调用正确的 setter 函数。


或者,如果您希望它更接近您的类组件,您可以将对象存储在状态中:

  let [books, setBooks] = useState([]);
  let [formValues, setFormValues] = useState({
    q: "",
    message: "Search For A Book to Begin"
  );

  const handleInputChange = (event) => {
    let { name, value } = event.target;
    setFormValues({ ...formValues, [name]: value })
  }

现在你有一个像以前一样处于状态的对象,并且可以动态地设置该对象的属性。


所有这一切都假设你想q从这个表单中设置一些东西,否则这变得微不足道:

const handleInputChange = event => { setQ(event.target.value) }
于 2021-09-02T19:47:27.143 回答