React 中的模态组件

huangapple go评论73阅读模式
英文:

Modal component in React

问题

I can help you with translating the non-code parts of your text. Here's the translation:

"I'm creating bookshop application. I'm quite freshmen in programing world. Whole application is created in react.

My mission is to create modal component from existing 'update' component.

The main component is books where is an update button, I would like the 'Update' component to appear as a modal component after pressing 'update - button' I have tried various ways to do this but I am stuck on this issue for good (2 days),"

If you have any specific questions or need further assistance, please feel free to ask.

英文:

I'm creating bookshop application. I'm quite freshmen in programing world. Whole application is created in react.

My mission is to create modal component from existing "update" component.

The main component is books where is an update button, I would like the "Update" component to appear as a modal component after pressing "update - button" I have tried various ways to do this but I am stuck on this issue for good (2 days),

import React from "react";
import { useState, useEffect } from "react";
import axios from "axios";
import { Link } from "react-router-dom";
import "../style/style.css"

const Books = () => {
  const [books, setBooks] = useState([]);

  useEffect(() => {
    const fetchAllBooks = async () => {
      try {
        const res = await axios.get("http://localhost:8800/books");
        setBooks(res.data);
      } catch (error) {
        console.log(error);
      }
    };
    fetchAllBooks();
  }, []);

  const handleDelete = async (id) => {
    try {
      await axios.delete(`http://localhost:8800/books/${id}`);
      window.location.reload();
    } catch (error) {
      console.log(error);
    }
  };

  return (
    <div className="form">
      <h1>The Greatest Bookshop</h1>
      <div className="books">
        {books.map((book) => (
          <div
            key={book.id}
            className="book"
          >
            {book.cover && (
              <img
                className="mainImg"
                src={book.cover}
                alt=""
              />
            )}
            <h2>{book.title}</h2>
            <p>{book.desc}</p>
            <span>${book.price}</span>
            <button
              className="delete"
              onClick={() => handleDelete(book.id)}
            >
              Delete
            </button>
            <button className="update">
              <Link
                to={`/update/${book.id}`}
                style={{ color: "inherit", textDecoration: "none" }}
              >
                Update
              </Link>
            </button>
          </div>
        ))}
      </div>
      <button className="newBook">
        <Link
          to="/Add"
          style={{ color: "inherit", textDecoration: "none" }}
        >
          Add new book
        </Link>
      </button>
    </div>
  );
};

export default Books;

And component which need to be modal is "Update":

import React, { useState, useEffect, useRef } from "react";
import { useNavigate, useLocation } from "react-router-dom";
import axios from "axios";
import "../style/update.css";
// import EditCover from "../__Test__/EditCover";

const Update = () => {

  const navigate = useNavigate();
  const location = useLocation();

  const bookId = location.pathname.split("/")[2];

  const [book, setBook] = useState({
    title: "",
    desc: "",
    price: null,
    cover: "",
  });

  useEffect(() => {
    const fetchCoverUrl = async () => {
      try {
        const res = await axios.get(`http://localhost:8800/books/${bookId}`);
        setBook((prevBook) => ({ ...prevBook, cover: res.data[0].cover}));
      } catch (error) {
        console.log(error);
      }
    };
    fetchCoverUrl();
  }, [bookId]);

  const fileInputRef = useRef(null);
 
  const changeImage = () => {
    fileInputRef.current.click();
  };

  const handleChange = (e) => {
    setBook((prev) => ({ ...prev, [e.target.name]: e.target.value }));
  };

  const handleFileChange = (e) => {
    const file = e.target.files[0];
    setBook((prev) => ({...prev, cover: URL.createObjectURL(file),
  }));
  };

  const handleClick = async (e) => {
    e.preventDefault();
    try {
      await axios.put("http://localhost:8800/books/" + bookId, book);
      navigate("/");
    } catch (error) {
      console.log(error);
    }
  };

  return (
    <div className="update-form">
      <div className="update-container">
        <h1>Update the Book</h1>
        <input
          type="text"
          placeholder="title"
          onChange={handleChange}
          name="title"
        />
        <input
          type="text"
          placeholder="desc"
          onChange={handleChange}
          name="desc"
        />
        <input
          type="number"
          placeholder="price"
          onChange={handleChange}
          name="price"
        />
        <input
          data-id="inputRef"
          type="file"
          placeholder="cover"
          ref={fileInputRef}
          onChange={handleFileChange}
          name="cover"
          style={{display: "none"}}
        />
        <button
          className="updateBtn"
          onClick={handleClick}
        >
          Update
        </button>
      </div>
      <div className="coverForm">
        {book.cover && (
              <img
                className="coverUpdate"
                src={book.cover}
                alt="Loading..."
                onClick={changeImage}
                style={{cursor: "pointer"}}
              />
        )}
      </div>
    </div>
  );
};

export default Update;

I am not really sure how i can figure existing "update" component to be a modal, i was basing on example:

import React, { useState } from 'react'
import "./test.css"


const ModalComponent = () => {

    const [isModal, setIsModal] = useState(false);
    
    const openModal = () => {
        setIsModal(true);
        
    }

    const closeModal = () => {
        setIsModal(false);
    }


  return (
    <div>
      <h1>Books</h1>
      <button onClick={openModal}>Update</button>

      {isModal && (
        <div className="modal">
          <div className="modal-content">
            <h2>Update book</h2>
            <button className="close-btn" onClick={closeModal}>Close</button>
          </div>
        </div>
      )}
    </div>
  )
}

export default ModalComponent

答案1

得分: 0

你需要将 update 组件包装在 modal-content 中,并在点击 update 按钮时打开模态框。

使用 HTML CSS JS 创建模态框

如果你只想使用这个模态框一次,就不需要创建一个单独的模态框组件。

英文:

You need to wrap update component in modal-content and open modal on click of update button.

Creating a Modal using HTML CSS JS

You dont need to create a separate component for Modal if you only want to use this modal one time.

答案2

得分: 0

如果你想让 Update 组件的内容在 ModalComponent 中打开,那么 Update 应该导入 ModalComponent 并将 UI 渲染到其中。ModalComponent 应该进行一些重构以接受和渲染一个 children 属性。

示例:

假设模态框在渲染/挂载时默认打开,在卸载时关闭。

const ModalComponent = ({ children, onClose }) => {
  return (
    <div className="modal">
      <div className="modal-content">
        <button className="close-btn" onClick={onClose}>Close</button>
        {children}
      </div>
    </div>
  );
};

从这里你有两个选择。你可以将 ModalComponent 导入到 Update 中并直接包裹 UI:

import React, { useState, useEffect, useRef } from "react";
import { useNavigate, useLocation, useParams } from "react-router-dom";
import axios from "axios";
import "../style/update.css";
// import EditCover from "../__Test__/EditCover";
import { ModalComponent } from "../path/to/ModalComponent";

const Update = () => {
  const navigate = useNavigate();
  const location = useLocation();
  const { bookId } = useParams();

  const [book, setBook] = useState({
    title: "",
    desc: "",
    price: null,
    cover: "",
  });

  useEffect(() => {
    const fetchCoverUrl = async () => {
      try {
        const res = await axios.get(`http://localhost:8800/books/${bookId}`);
        setBook((prevBook) => ({ ...prevBook, cover: res.data[0].cover}));
      } catch (error) {
        console.log(error);
      }
    };
    fetchCoverUrl();
  }, [bookId]);

  ...

  return (
    <ModalComponent onClose={() => navigate(-1)}> // <-- 返回到列表
      <div className="update-form">
        <div className="update-container">
          ...
        </div>
        ...
      </div>
    </ModalComponent>
  );
};

export default Update;

或者你可以创建一个布局路由组件,将 Update 路由渲染到模态框中。

import { Outlet, useNavigate } from "react-router-dom";
import { ModalComponent } from "../path/to/ModalComponent";

const UpdateLayout = () => {
  const navigate = useNavigate();

  return (
    <ModalComponent onClose={() => navigate(-1)}>
      <Outlet />
    </ModalComponent>
  );
};
<Routes>
  ...
  <Route element={<UpdateLayout />}>
    <Route path="/update/:bookId" element={<Update />} />
  </Route>
  ...
</Routes>
英文:

If you want the Update component content to open in the ModalComponent then Update should import ModalComponent and render the UI into it. ModalComponent should be refactored a bit to take and render a children prop.

Example:

Assume the modal is open by default when rendered/mounted, closed when unmounted.

const ModalComponent = ({ children, onClose }) => {
  return (
    <div className="modal">
      <div className="modal-content">
        <button className="close-btn" onClick={onClose}>Close</button>
        {children}
      </div>
    </div>
  );
};

From here you have a couple choices. You can import ModalComponent into Update and wrap directly the ui there:

import React, { useState, useEffect, useRef } from "react";
import { useNavigate, useLocation, useParams } from "react-router-dom";
import axios from "axios";
import "../style/update.css";
// import EditCover from "../__Test__/EditCover";
import { ModalComponent } from "../path/to/ModalComponent";

const Update = () => {
  const navigate = useNavigate();
  const location = useLocation();
  const { bookId } = useParams();

  const [book, setBook] = useState({
    title: "",
    desc: "",
    price: null,
    cover: "",
  });

  useEffect(() => {
    const fetchCoverUrl = async () => {
      try {
        const res = await axios.get(`http://localhost:8800/books/${bookId}`);
        setBook((prevBook) => ({ ...prevBook, cover: res.data[0].cover}));
      } catch (error) {
        console.log(error);
      }
    };
    fetchCoverUrl();
  }, [bookId]);

  ...

  return (
    <ModalComponent onClose={() => navigate(-1)}> // <-- navigate back to list
      <div className="update-form">
        <div className="update-container">
          ...
        </div>
        ...
      </div>
    </ModalComponent>
  );
};

export default Update;

or you can create a layout route component that renders the Update route into the modal.

import { Outlet, useNavigate } from "react-router-dom";
import { ModalComponent } from "../path/to/ModalComponent";

const UpdateLayout = () => {
  const navigate = useNavigate();

  return (
    <ModalComponent onClose={() => navigate(-1)}>
      <Outlet />
    </ModalComponent>
  );
};
<Routes>
  ...
  <Route element={<UpdateLayout />}>
    <Route path="/update/:bookId" element={<Update />} />
  </Route>
  ...
</Routes>

huangapple
  • 本文由 发表于 2023年5月11日 19:08:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/76226961.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定