简体   繁体   English

在 React 中单击另一个组件中的按钮后如何显示 Modal?

[英]How to show Modal after clicking a button in another component in React?

I have this two components:我有这两个组件:

import React, { useState, useEffect } from "react";
import axios from "axios";
import Button from "../../../components/Button";
import NewAreaModal from "./NewAreaModal";

function GestioneAree() {

    const [aree, setAree] = useState([]);
    const [show, setShow] = useState(false);

    useEffect(() => {
        axios.get("http://localhost:8080/aree/all").then((res) => {
            setAree(res.data);
            console.log(res.data);
        });
    }, []);

    const showModal = () => {
        setShow(true);
    }

    return (
        <div className="bg-white rounded-lg">
            <div className="px-4 py-5 sm:px-6 rounded">
                <div className="-ml-4 -mt-2 flex items-center justify-between flex-wrap sm:flex-nowrap">
                    <div className="ml-4 mt-2">
                        <h3 className="text-lg leading-6 font-medium text-gray-900">Aree nel Sistema</h3>
                    </div>
                    <div className="ml-4 mt-2 flex-shrink-0">
                        <Button type="button" decoration="primary" text="Crea Nuova Area" onClick={showModal}/>
                    </div>
                </div>
            </div>
            <div className="flex flex-col">
                <div className="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
                    <div className="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8">
                        <div className="shadow overflow-hidden border-t border-gray-200 sm:rounded-lg">
                            <table className="min-w-full divide-y divide-gray-200">
                                <thead className="bg-gray-50">
                                    <tr>
                                        <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
                                            Toponimo
                                        </th>
                                        <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
                                            Territorio
                                        </th>
                                        <th scope="col" className="relative px-6 py-3">
                                            <span className="sr-only">Edit</span>
                                        </th>
                                    </tr>
                                </thead>
                                <tbody>
                                    {aree.map((area) => (
                                        <tr key={area.idArea} className="bg-white border-b">
                                            <td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">{area.toponimo}</td>
                                            <td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">{area.territorio.nome}</td>
                                            <td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
                                                <button type="button" className="text-green-600 hover:text-green-900" >
                                                    Modifica
                                                </button>
                                            </td>
                                        </tr>
                                    ))}
                                </tbody>
                            </table>
                            <NewAreaModal show={show} />
                        </div>
                    </div>
                </div>
            </div>
        </div>
    );
}

export default GestioneAree;

and

import React, { useState, useRef, Fragment } from "react";
import { Dialog, Transition } from "@headlessui/react";
import Button from "../../../components/Button";

function NewAreaModal() {
    const [open, setOpen] = useState(true);

    const cancelButtonRef = useRef(null);

    return (
        <Transition.Root show={open}>
            <Dialog as="div" className="relative z-10" initialFocus={cancelButtonRef} onClose={setOpen}>
                <Transition.Child as={Fragment} enter="ease-out duration-300" enterFrom="opacity-0" enterTo="opacity-100" leave="ease-in duration-200" leaveFrom="opacity-100" leaveTo="opacity-0">
                    <div className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
                </Transition.Child>
                <div className="fixed z-10 inset-0 overflow-y-auto">
                    <div className="flex items-end sm:items-center justify-center min-h-full p-4 text-center sm:p-0">
                        <Transition.Child as={Fragment} enter="ease-out duration-300" enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" enterTo="opacity-100 translate-y-0 sm:scale-100" leave="ease-in duration-200" leaveFrom="opacity-100 translate-y-0 sm:scale-100" leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95">
                            <Dialog.Panel className="relative bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:max-w-lg sm:w-full">
                                <div className="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
                                    {
                                        // Form here
                                    }
                                </div>
                                <div className="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
                                    <Button type="button" text="Crea Area" decoration="primary" otherCSS={"w-full justify-center sm:ml-3 sm:w-auto sm:text-sm"} onClick={() => setOpen(false)}/>
                                    <Button type="button" text="Annulla" decoration="secondary" otherCSS={"w-full justify-center sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"} onClick={() => setOpen(false)} ref={cancelButtonRef}/>
                                </div>
                            </Dialog.Panel>
                        </Transition.Child>
                    </div>
                </div>
            </Dialog>
        </Transition.Root>
    );
}

export default NewAreaModal;

What I want to do is opening the component NewAreaModal.js when I'm clicking the Crea Nuova Area button... what is wrong with my code?我想要做的是在单击Crea Nuova 区域按钮时打开组件NewAreaModal.js ......我的代码有什么问题?

I have tried many ways but it dosen't work.我尝试了很多方法,但它不起作用。 For example, I tried to pass a prop to NewAreaModal called show and then I putted this variable inside useState in const [open, setOpen] = useState(show) but the <Transition> component says that is missing the show prop even if I passed a boolean variable...例如,我尝试将一个名为show的道具传递给useState ,然后将此变量放入const [open, setOpen] = useState(show)的 useState 中,但<Transition>组件说即使我通过了也缺少显示道具一个布尔变量...

This code is missing some functions for the comunication with the backend because I just started!这段代码缺少一些与后端通信的功能,因为我刚刚开始!

I'm practicing React since 2 months so I don't have a lot of experience...我从两个月开始练习 React,所以我没有很多经验......

Thank you guys for the patience!谢谢大家的耐心等待!

Your parent component seems ok to me.你的父组件对我来说似乎没问题。 It would say the issue comes from how you handle the button interaction and props in the child.它会说问题来自您如何处理孩子中的按钮交互和道具。

I would start by trying something like that :我会先尝试这样的事情:

Parent:家长:

   import NewAreaModal from "./NewAreaModal";

function GestioneAree() {

    const [aree, setAree] = useState([]);
    const [show, setShow] = useState(false);

    useEffect(() => {
        axios.get("http://localhost:8080/aree/all").then((res) => {
            setAree(res.data);
            console.log(res.data);
        });
    }, []);

    const showModal = () => {
        setShow(true);
    }

    return (
        <div className="bg-white rounded-lg">
            <div className="px-4 py-5 sm:px-6 rounded">
                <div className="-ml-4 -mt-2 flex items-center justify-between flex-wrap sm:flex-nowrap">
                    <div className="ml-4 mt-2">
                        <h3 className="text-lg leading-6 font-medium text-gray-900">Aree nel Sistema</h3>
                    </div>
                    <div className="ml-4 mt-2 flex-shrink-0">
                        <Button type="button" decoration="primary" text="Crea Nuova Area" onClick={showModal}/>
                    </div>
                </div>
            </div>
            <div className="flex flex-col">
                <div className="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
                    <div className="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8">
                        <div className="shadow overflow-hidden border-t border-gray-200 sm:rounded-lg">
                            <table className="min-w-full divide-y divide-gray-200">
                                <thead className="bg-gray-50">
                                    <tr>
                                        <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
                                            Toponimo
                                        </th>
                                        <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
                                            Territorio
                                        </th>
                                        <th scope="col" className="relative px-6 py-3">
                                            <span className="sr-only">Edit</span>
                                        </th>
                                    </tr>
                                </thead>
                                <tbody>
                                    {aree.map((area) => (
                                        <tr key={area.idArea} className="bg-white border-b">
                                            <td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">{area.toponimo}</td>
                                            <td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">{area.territorio.nome}</td>
                                            <td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
                                                <button type="button" className="text-green-600 hover:text-green-900" >
                                                    Modifica
                                                </button>
                                            </td>
                                        </tr>
                                    ))}
                                </tbody>
                            </table>
                            <NewAreaModal show={show} setShow={(bool) => setShow(bool) />
                        </div>
                    </div>
                </div>
            </div>
        </div>
    );
}

export default GestioneAree;

Child :孩子 :

import React, { useState, useRef, Fragment } from "react";
 import { Dialog, Transition } from "@headlessui/react";
 import Button from "../../../components/Button";
        
    function NewAreaModal({show, setShow}) {
    
        const cancelButtonRef = useRef(null);
   
    
        return (
            <Transition.Root show={show}>
                <Dialog as="div" className="relative z-10" initialFocus={cancelButtonRef} onClose={setOpen}>
                    <Transition.Child as={Fragment} enter="ease-out duration-300" enterFrom="opacity-0" enterTo="opacity-100" leave="ease-in duration-200" leaveFrom="opacity-100" leaveTo="opacity-0">
                        <div className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
                    </Transition.Child>
                    <div className="fixed z-10 inset-0 overflow-y-auto">
                        <div className="flex items-end sm:items-center justify-center min-h-full p-4 text-center sm:p-0">
                            <Transition.Child as={Fragment} enter="ease-out duration-300" enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" enterTo="opacity-100 translate-y-0 sm:scale-100" leave="ease-in duration-200" leaveFrom="opacity-100 translate-y-0 sm:scale-100" leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95">
                                <Dialog.Panel className="relative bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:max-w-lg sm:w-full">
                                    <div className="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
                                        {
                                            // Form here
                                        }
                                    </div>
                                    <div className="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
                                        <Button type="button" text="Crea Area" decoration="primary" otherCSS={"w-full justify-center sm:ml-3 sm:w-auto sm:text-sm"} onClick={() => setShow(false)}/>
                                        <Button type="button" text="Annulla" decoration="secondary" otherCSS={"w-full justify-center sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"} onClick={() => setShow(false)} ref={cancelButtonRef}/>
                                    </div>
                                </Dialog.Panel>
                            </Transition.Child>
                        </div>
                    </div>
                </Dialog>
            </Transition.Root>
        );
    }
    
    export default NewAreaModal;

I have tried many ways but it dosen't work.我尝试了很多方法,但它不起作用。 For example, I tried to pass a prop to NewAreaModal called show and then I putted this variable inside useState in const [open, setOpen] = useState(show) but the <Transition> component says that is missing the show prop even if I passed a boolean variable...例如,我尝试将一个名为show的道具传递给useState ,然后将此变量放入const [open, setOpen] = useState(show)的 useState 中,但<Transition>组件说即使我通过了也缺少显示道具一个布尔变量...

Passing in the show prop is the right idea, but you are missing a few things, and overcomplicating in some other areas.传递show prop 是正确的想法,但是你遗漏了一些东西,并且在其他一些方面过于复杂。

The code in the GestioneAree component looks correct to me - you have a show state variable that you pass in to NewAreaModal , and set this to true when the button is clicked to open the modal. GestioneAree组件中的代码对我来说看起来是正确的 - 您有一个show状态变量,您将它传递给NewAreaModal ,并在单击按钮以打开模式时将其设置为true This is all correct.这都是正确的。 All you need to do is to have NewAreaModal use that to determine whether to show the component's contents or not.您需要做的就是让NewAreaModal使用它来确定是否显示组件的内容。

To do that you need to first have NewAreaModal accept show as a prop:为此,您需要首先让NewAreaModal接受show作为道具:

function NewAreaModal({ show }) {
  // component code
}

This show prop will then be the only thing that controls whether the modal is open or not.这个show prop 将是唯一控制模态是否打开的东西。 So you don't need, or want, any state here.所以你不需要或想要这里的任何状态。 So remove this line:所以删除这一行:

const [open, setOpen] = useState(true);

and instead use the show prop where you were using open before - in particular pass it to the Transition.Root , which is component you don't show but I assume this is what will actually show or hide the contents:而是使用您之前使用openshow道具 - 特别是将其传递给Transition.Root ,这是您不显示的组件,但我认为这是实际显示或隐藏内容的组件:

<Transition.Root show={show}>

That's essentially it, but there's another important way you will have to change your code.本质上就是这样,但是还有另一种重要的方式,你将不得不改变你的代码。 Your modal component appears to have a button inside it to close the modal.您的模态组件内部似乎有一个按钮来关闭模态。 That would work when you had the open (or show ) property in state, as you could have the button set that state to false .当您在 state 中拥有open (或show )属性时,这将起作用,因为您可以让按钮将该 state 设置为false That doesn't work directly when show is a prop instead.show是道具时,这不能直接起作用。

But there's an easy fix - to simply have your modal component accept a function that closes the modal.但是有一个简单的解决方法——让你的模态组件接受一个关闭模态的函数。

You already have an openModal function defined in your parent component:您已经在父组件中定义了一个openModal函数:

const showModal = () => {
    setShow(true);
}

and you can do something similar to make a "closeModal" function:你可以做一些类似的事情来制作一个“closeModal”函数:

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

Then you can pass this function in as a prop to NewAreaModal :然后你可以将此函数作为道具传递给NewAreaModal

<NewAreaModal show={show} closeModal={closeModal}/>

Finally, NewAreaModal needs to accept this prop:最后, NewAreaModal需要接受这个道具:

function NewAreaModal({ show, closeModal }) {
  // component code
}

and call it when the close button is clicked, by replacing onClick={() => setOpen(false)} by onClick={closeModal} for each button where you have this.并在单击关闭按钮时调用它,方法是将onClick={() => setOpen(false)}替换为onClick={closeModal}为您拥有此按钮的每个按钮。

(Note that if you are using NewAreaModal elsewhere you will need to ensure this closeModal prop is passed in each time it is used.) (请注意,如果您在其他地方使用NewAreaModal ,则需要确保每次使用此closeModal时都将其传入。)

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

相关问题 单击 React 中的模态关闭按钮后如何重置模态输入状态? - How to reset the Modal input states after clicking the modal close button in React? 单击模态按钮如何调用另一个函数? - How to call another function on clicking of Modal button? 单击模态中的图像后如何显示图像? - How to show image after clicking the image in modal? 单击另一个按钮时如何显示一个按钮? - How to show a button, when clicking on another button? 单击带有asp.net core MVC的按钮后显示模式 - Show modal after clicking on a button with asp.net core MVC Reactjs:从另一个组件单击按钮后未显示子组件 - Reactjs: child component not showing after clicking button from another component 单击按钮后,Bootstrap5 模态未在 React.js 中显示 - Bootstrap5 modal not displaying in React.js after clicking on the button 如何通过单击 React 中的按钮来路由 class 组件? - How to route class component by clicking button in React? 如何通过单击 create-react-app 中的按钮从位于另一个 js 文件中的另一个组件访问函数? - How to access a function from another component that is located in another js file by clicking a button in create-react-app? 单击跨度后如何显示按钮? - How to show button after clicking on a span?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM