javascript React状态管理问题

rsaldnfx  于 2023-01-07  发布在  Java
关注(0)|答案(1)|浏览(114)

我使用API在应用程序中检索图书详细信息,有两种途径:一个包含表单和搜索结果,另一个包含每个搜索结果的完整详细信息。当前,详细信息页面上有一个链接,可将我带回到表单页面,但我希望保留表单页面的状态,并在单击链接时显示搜索结果,而不仅仅是表单。如何才能做到这一点?
你可以检查我下面的代码.
BookDetails.jsx

import { useParams } from "react-router-dom";
import fetchBookDetails from "../hooks/fetchBookDetails";
import { useQuery } from "@tanstack/react-query";
import { Link } from "react-router-dom";
import notFoundImage from "../assets/react.svg";
import Header from "./Header";

const BookDetails = () => {
  const { id } = useParams();
  const results = useQuery(["book", id], fetchBookDetails);

  if (results.isLoading) {
    return <div>Loading...</div>;
  }

  if (results.isError) {
    return <div>Book with id {id} not found.</div>;
  }

  if (results.data) {
    return (
      <div>
        <Header />
        <Link to="/">
          <button className="back">Back</button>
        </Link>
        <div className="book-details">
          <img
            src={
              results.data.volumeInfo.imageLinks
                ? results.data.volumeInfo.imageLinks.thumbnail
                : notFoundImage
            }
            alt={results.data.volumeInfo.title}
          />
          <h1>{results.data.volumeInfo.title}</h1>
          <p>{results.data.volumeInfo.authors}</p>
          
        </div>
      </div>
    );
  }
};

export default BookDetails;

SearchForm.jsx

const SearchForm = ({ onSubmit }) => {
  const handleSubmit = (e) => {
    e.preventDefault();
    onSubmit(e.target.elements.book.value);
  };

  return (
    <>
      {" "}
      <div>
        <form onSubmit={handleSubmit}>
          <label htmlFor="book">
            Book Name:
            <input type="text" name="book" />
          </label>
          <button type="submit">Submit</button>
        </form>
      </div>
    </>
  );
};

export default SearchForm;

Seachresult.jsx

import React from "react";
import { Link } from "react-router-dom";
import notFoundImage from "../assets/react.svg";

const SearchResults = ({ results }) => {
  return results.isLoading ? (
    <div>Loading...</div>
  ) : results.isError ? (
    <div>{results.error.message}</div>
  ) : (
    <div className="books">
      {results.data.items.map((item, i) => {
        return (
          <Link to={`/book/${item.id}`} key={item.id}>
            <div key={item.id} className="book border-2-red-500">
              <p>{i + 1}</p>

              <img
                src={
                  item.volumeInfo.imageLinks
                    ? item.volumeInfo.imageLinks.thumbnail
                    : notFoundImage
                }
                alt={item.volumeInfo.title}
              />

              <h3>{item.volumeInfo.title}</h3>
              <p>{item.volumeInfo.authors}</p>
            </div>
          </Link>
        );
      })}
    </div>
  );
};

export default SearchResults;

Home.jsx

import { useState } from "react";
import { useQuery } from "@tanstack/react-query";
import fetchBooks from "../hooks/fetchBooks";
import SearchResults from "./SearchResults";

import SearchForm from "./SearchForm";
import Header from "./Header";

const Home = () => {
  const [book, setBook] = useState(null);

  const results = useQuery(["search", book], fetchBooks);

  return (
    <main>
      <Header />

      <SearchForm onSubmit={setBook} />
      <SearchResults results={results} />
    </main>
  );
};

export default Home;

最后是App.jsx

import "./App.css";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import Home from "./components/Home";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import BookDetails from "./components/BookDetails";

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: Infinity,
      cacheTime: Infinity,
    },
  },
});

function App() {
  return (
    <BrowserRouter>
      <QueryClientProvider client={queryClient}>
        <Routes>
          <Route path="/book/:id" element={<BookDetails />} />
          <Route path="/" element={<Home />} />
        </Routes>
      </QueryClientProvider>
    </BrowserRouter>
  );
}

export default App;
noj0wjuj

noj0wjuj1#

您可以使用React Context API,创建一个Context来 Package 您想要授予访问这些状态的权限的组件,然后您可以以“全局”方式管理状态,以便在来回切换时保持其完整性。
您可以查看以下示例:

import React, { useState, createContext, useCallback, useContext } from 'react';
import { uuid } from 'uuidv4';
import ToastContainer from '../components/ToastContainer';

interface ToastContextData {
  addToast(messages: Omit<ToastMessage, 'id'>): void;
}
export interface ToastMessage {
  id: string;
  type?: 'success' | 'error' | 'info';
  title: string;
  description: string;
}

const ToastContext = createContext<ToastContextData>({} as ToastContextData);

const ToastProvider: React.FC = ({ children }) => {
  const [messages, setMessages] = useState<ToastMessage[]>([]);

  const addToast = useCallback(
    ({ type, title, description }: Omit<ToastMessage, 'id'>) => {
      const id = uuid();

      const toast = {
        id,
        type,
        title,
        description,
      };

      setMessages((state) => [...state, toast]);
    },
    []
  );

  }, []);

  return (
    <ToastContext.Provider value={{ addToast }}>
      {children}
      <ToastContainer messages={messages} />
    </ToastContext.Provider>
  );
};

function useToast(): ToastContextData {
  const context = useContext(ToastContext);

  if (!context) {
    throw new Error('useToast must be used within a ToastProvider');
  }
  return context;
}

export { ToastProvider, useToast };

相关问题