Home > Software engineering >  UseEffect with empty dependencies and state values
UseEffect with empty dependencies and state values

Time:09-29

I have the code below. The problem is, like the documentation says, if you use an useEffect with an empty array of dependencies, you're stuck with the initial values of the states or variables. What can I do to solve the if in line 7

const UserNotification = ({ notificationData, unreadNotifications, setUnreadNotifications }) => {
  const [isOpenNotification, setIsOpenNotification] = useState(false);

  const handleClickOutside = (e) => {
    const parent = document.querySelector('[data-notification]');
    if (!parent.contains(e.target)) {
      if (isOpenNotification && unreadNotifications) {
        setUnreadNotifications((s) => false);
      }
      setIsOpenNotification((s) => false);
    }
  };

  const handleClickReadAll = () => {
    setUnreadNotifications((s) => false);
  };

  useEffect(() => {
    document.addEventListener('mousedown', handleClickOutside);
    return () => document.removeEventListener('mousedown', handleClickOutside);
  }, []);
  return (
    <div
      data-notification
    >
      <div className="relative">
        <ClassicButton
          type="custom"
          onClick={() => setIsOpenNotification((s) => !s)}
          className="text-custom-gray-3 rounded-full"
          icon={<Icon path={mdiBell} size={1.2} color={theme.colors['custom-gray-2']} />}
        />
        { unreadNotifications && (
          <div className="absolute border-0 rounded-full w-[7px] h-[7px] bg-red-600 bottom-0 right-0" />
        ) }
      </div>
      {isOpenNotification && (
        <NotificationList
          data={notificationData}
          handleClickReadAll={handleClickReadAll}
        />
      )}
    </div>
  );
};
export default UserNotification;

CodePudding user response:

You update the useEffect when required

const handleClickOutside = useCallback((e) => {
  const parent = document.querySelector('[data-notification]');
  if (!parent.contains(e.target)) {
    if (isOpenNotification && unreadNotifications) {
      setUnreadNotifications(false);
    }
    setIsOpenNotification(false);
  }
}, [isOpenNotification, unreadNotifications]);


useEffect(() => {
  document.addEventListener('mousedown', handleClickOutside);
  return () => document.removeEventListener('mousedown', handleClickOutside);
}, [handleClickOutside]);

CodePudding user response:

Use a ref (openAndUnread) to hold the boolean value of isOpenNotification && unreadNotifications, and update it in another useEffect block.

const UserNotification = ({ notificationData, unreadNotifications, setUnreadNotifications }) => {
  const [isOpenNotification, setIsOpenNotification] = useState(false);
  const openAndUnread = useRef(false);

  const handleClickReadAll = () => {
    setUnreadNotifications(false);
  };
  
  useEffect(() => {
    openAndUnread.current = isOpenNotification && unreadNotifications;
  });

  useEffect(() => {
    const handleClickOutside = (e) => {
      const parent = document.querySelector('[data-notification]');
      if (!parent.contains(e.target)) {
        if (openAndUnread.current) {
          setUnreadNotifications(false);  
        }
        
        setIsOpenNotification(false);
      }
    };
  
    document.addEventListener('mousedown', handleClickOutside);
    return () => document.removeEventListener('mousedown', handleClickOutside);
  }, []);
  • Related