[英]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 insideuseState
inconst [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:而是使用您之前使用open
的show
道具 - 特别是将其传递给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.