reactjs 触发时使用旧状态数据的React超时

2ic8powd  于 2023-01-30  发布在  React
关注(0)|答案(1)|浏览(106)

我正在尝试为React创建一个简单的通知提供程序,如果你点击通知,它会非常好地工作。但是,当使用从父级传递到子级的"finished"函数时,子级的超时函数似乎使用了一个旧的状态。几乎就像timeout快照数据,或者setState在超时完成后排队一样。可以使用timeout吗,还是我需要重新考虑一下汽车消失的事

import styles from "@styles/Notification.module.scss";
import React, { createContext, useState } from "react";
import NotificationCard from "@components/Notifications/Notification";
import { uuid4 } from "@sentry/utils";

export interface NotificationInterface {
  notifications: Notification[];
  info(notification: Notification): void;
  success(notification: Notification): void;
  warning(notification: Notification): void;
  error(notification: Notification): void;
}

export interface Notification {
  id?: string;
  message: string;
  level?: NotificationLevel;
  timeout?: number;
  delay?: number;
}

export enum NotificationLevel {
  INFO = "info",
  SUCCESS = "success",
  WARNING = "warning",
  ERROR = "error"
}

export const NotificationContext = createContext<NotificationInterface>({} as NotificationInterface);

export const NotificationProvider = ({ children }: { children?: JSX.Element }) => {
  const [notifications, setNotifications] = useState<Notification[]>([]);

  const createNotification = (notification: Notification): Notification => {
    return {
      id: uuid4(),
      level: notification.level || NotificationLevel.INFO,
      message: notification.message || "",
      timeout: notification.timeout || 5000,
      delay: notification.delay || 0
    };
  };

  const info = (notification: Notification) => {
    setNotifications([...notifications, createNotification({ ...notification, level: NotificationLevel.INFO })]);
  };

  const success = (notification: Notification) => {
    setNotifications([...notifications, createNotification({ ...notification, level: NotificationLevel.SUCCESS })]);
  };

  const warning = (notification: Notification) => {
    setNotifications([...notifications, createNotification({ ...notification, level: NotificationLevel.WARNING })]);
  };

  const error = (notification: Notification) => {
    setNotifications([...notifications, createNotification({ ...notification, level: NotificationLevel.ERROR })]);
  };

  const finished = (notification: Notification) => {
    setNotifications(notifications.filter((n) => n.id !== notification.id));
  };

  return (
    <NotificationContext.Provider
      value={{
        notifications,
        info,
        success,
        warning,
        error
      }}
    >
      <div className={styles.notificationContainer}>
        {notifications.map((notification) => (
          <NotificationCard key={notification.id} notification={notification} onFinished={(n) => finished(n)} />
        ))}
      </div>
      {children}
    </NotificationContext.Provider>
  );
};
import styles from "@styles/Notification.module.scss";
import { Notification } from "@utils/notificationProvider";
import { useEffect, useState } from "react";

const NotificationCard = ({
  notification,
  onFinished
}: {
  notification: Notification;
  onFinished?: (notification: Notification) => void;
}) => {
  const [isOpen, setIsOpen] = useState(true);

  const close = () => {
    setIsOpen(false);

    setTimeout(() => {
      if (onFinished) {
        onFinished(notification);
      }
    }, 500);
  };

  useEffect(() => {
    const timeout = setTimeout(() => {
      close();
    }, notification.timeout);

    return () => {
      clearTimeout(timeout);
    };
  }, []);

  return (
    <div onClick={() => close()} className={isOpen ? styles.notificationCard : styles.notificationCardClosed}>
      {notification.message}
    </div>
  );
};

export default NotificationCard;
42fyovps

42fyovps1#

当使用异步代码时,(但我建议几乎总是使用它)。当使用旧状态设置你的状态时,使用回调而不是值。因为状态的值在重新呈现后会改变,但在回调属性中,i是立即改变的。
示例:
而不是这个

const info = (notification: Notification) => {
    setNotifications([...notifications, createNotification({ ...notification, level: NotificationLevel.INFO })]);
  };

用这个

const info = (notification: Notification) => {
    setNotifications((oldNotifications)=>[...oldNotifications, createNotification({ ...notification, level: NotificationLevel.INFO })]);
  };

这样,您就可以始终使用当前数据

相关问题