Пользователь получает полный контроль над внешним компонентом вместо компонента, используемого в

#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? И с крючком все в порядке?