#javascript #reactjs #react-hooks
Вопрос:
Я создаю панель приложений с интерфейсом material. Когда я использую пользовательский крючок. для управления дочерним компонентом он также управляет всем родительским компонентом… Моя цель состоит в том, чтобы использовать этот крючок, чтобы удалить компонент всякий раз, когда щелчок производится за пределами компонента
Вот мой пользовательский крючок
useListener.js
import { useEffect, useState, useRef } from "react"; export const useListener = (active, ref) =gt; { ref = useRef(); const [open, setOpen] = useState((active = false)); useEffect(() =gt; { function handleClickOutside(event) { if (ref.current amp;amp; !ref.current.contains(event.target)) { setOpen(!open); return; } } // Bind the event listener document.body.addEventListener("click", handleClickOutside); return () =gt; { // Unbind the event listener on clean up document.body.removeEventListener("click", handleClickOutside); }; }, [open, ref]); return [open, ref]; };
когда я использую его в компоненте, разрушая его с помощью
const [open, ref] = useListener()
и используйте его внутри компонента, я установил open, чтобы компонент появлялся и исчезал с помощью CSS..
display: open ? 'block' : 'none'
Теперь, когда я использую этот компонент, в котором используется этот крючок, когда я нажимаю на этот компонент, он появляется, и когда я нажимаю за пределами компонента (в любом месте тела), он исчезает, что совершенно нормально… Но проблема в том, что когда я нажимаю на родительский компонент, в котором используется этот компонент, он также заставляет появиться этот дочерний компонент… Вот мой дочерний компонент…
Profile.js
import React from "react"; import Paper from "@mui/material/Paper"; import Box from "@mui/material/Box"; import cover from "../assets/cover.webp"; import profilepic from "../assets/profilepic.webp"; import Button from "@mui/material/Button"; import Typography from "@mui/material/Typography"; import { LogoutIcon } from "../assets/LogoutIcon"; import { ChangePasswordIcon } from "../assets/ChangePasswordIcon"; import { useListener } from "../../../hooks/useListener"; const logout = () =gt; { localStorage.removeItem("authorization"); localStorage.removeItem("user"); localStorage.removeItem("permissions"); window.location.reload(false); }; const Profile = () =gt; { const [open, profileRef] = useListener(); console.log(profileRef.current); return ( lt;Box ref={profileRef} sx={{ display: open ? "inline" : "none", width: "190px", }} gt; lt;Paper elevation={2}gt; lt;Box sx={{ display: "flex", flexDirection: "column", alignItems: "center", }} gt; lt;img src={cover} alt="Cover" style={{ width: "190px" }}gt;lt;/imggt; lt;img src={profilepic} alt="Profile" style={{ height: "62px", width: "62px", borderRadius: "50%" }} gt;lt;/imggt; lt;Typography variant="button" display="block" gutterBottomgt; Username lt;/Typographygt; lt;Buttongt; lt;Box sx={{ display: "flex", flexDirection: "row" }}gt; lt;ChangePasswordIcon sx={{ height: "18px", width: "18px" }} /gt; lt;Typography variant="body1" gutterBottomgt; Change password lt;/Typographygt; lt;/Boxgt; lt;/Buttongt; lt;Button onClick={logout}gt; lt;Box sx={{ display: "flex", flexDirection: "row" }}gt; lt;LogoutIcon sx={{ width: "16px", height: "16px" }} /gt; lt;Typography variant="body1" gutterBottomgt; Logout lt;/Typographygt; lt;/Boxgt; lt;/Buttongt; lt;/Boxgt; lt;/Papergt; lt;/Boxgt; ); }; export default Profile;
И это родительский компонент…
TopbarContents.js
import React, { useState } from "react"; import Box from "@mui/material/Box"; import Button from "@mui/material/Button"; import Typography from "@mui/material/Typography"; import profilepic from "../assets/profilepic.webp"; import Profile from "./Profile"; export const TopbarContents = () =gt; { const [profileActive, toggleProfile] = useState(false); const openProfile = () =gt; { toggleProfile(true); }; return ( lt;Box sx={{ width: "100%" }}gt; lt;Box sx={{ width: "100%", display: "flex", alignItems: "center", }} gt; lt;Box sx={{ flexGrow: 1 }}gt; lt;Typography sx={{ color: "#494343" }} variant="h6" noWrap component="div" gt; Dashboard lt;/Typographygt; lt;/Boxgt; lt;Box sx={{ height: "45px", width: "160px", borderRadius: 2, display: "flex", flexDirection: "column", justifyContent: "center", border: "1px solid #e0e0e0", pl: "8px", }} gt; lt;Typography sx={{ color: "#2E4299", pt: 1 }} variant="caption"gt; Case study lt;/Typographygt; lt;Typography sx={{ color: "#494343" }} variant="overline"gt; Trial ID: NC48023194 lt;/Typographygt; lt;/Boxgt; lt;Button color="guava" variant="contained" size="medium" sx={{ fontFamily: "Poppins", mr: 6, ml: 3 }} gt; Case Study lt;/Buttongt; lt;Button onClick={openProfile}gt; lt;img src={profilepic} alt="Profile" style={{ height: "62px", width: "62px", borderRadius: "50%" }} gt;lt;/imggt; lt;/Buttongt; lt;/Boxgt; lt;Box sx={{ display: profileActive ? "inline" : "none", flexDirection: "column", }} gt; lt;Profile /gt; lt;/Boxgt; lt;/Boxgt; ); };
Комментарии:
1. Измените
const [open, profileRef] = useListener();
наconst [open, ref] = useListener();
. Вы не можете импортировать файл профиля из customHook, если вы его не экспортировали.2. @davoodSandoghsaz Я не понял. Должен ли я просто изменить профиль с помощью ref? И с крючком все в порядке?