React Redux:自定义钩子中函数内外变量值不一致

k10s72fa  于 12个月前  发布在  React
关注(0)|答案(1)|浏览(154)

我在一个使用Redux的自定义React钩子中遇到了一个问题。这个问题与同一个钩子中函数内外的变量值不一致有关。下面是简化的代码:

import { useAppSelector } from "Redux/helpers";
import { selectAgentState } from "Redux/slices/agentSlice";

const useRemoveRoomNotif = () => {
  const notifications = useAppSelector((state) => selectAgentState(state).notifications);
  console.log("Outside function:", notifications);

  const removeNotif = (rid: string, markNotificationsAsRead) => {
    console.log("Inside function:", notifications);
    const ntf = notifications.filter((notif) => notif.roomID === rid && !notif.isRead);
    if (ntf.length !== 0) markNotificationsAsRead(ntf);
  };

  return { removeNotif };
};

export default useRemoveRoomNotif;

字符串
问题是removeNotif函数内部的notifications值与函数外部的值不同。我假设因为它是同一个变量,所以值应该是相同的。
我尝试使用useStateuseEffectuseRef来确保在函数中使用正确的值:

const useRemoveRoomNotif = () => {
  const notifications = useAppSelector((state) => selectAgentState(state).notifications);
  const [update, setUpdate] = useState(false);
  const [id, seId] = useState("");
  const markAsReadRef = useRef<(notifications: INotification[]) => void>();

  useEffect(() => {
    if (!update) return;
    const ntf = notifications.filter((notif) => notif.roomID === id && !notif.isRead);
    if (ntf.length !== 0 && markAsReadRef.current) {
      markAsReadRef.current(ntf);
    }
    setUpdate(false);
  }, [notifications, markAsReadRef, id, update, setUpdate]);

  const removeNotif = useCallback(
    (rid: string, markNotificationsAsRead: (notifications: INotification[]) => void) => {
      seId(rid);
      markAsReadRef.current = markNotificationsAsRead;
      setUpdate(true);
    },
    [notifications, seId, markAsReadRef]
  );

  return { removeNotif };
};

export default useRemoveRoomNotif;


有人能帮助我理解为什么最初的实施没有按预期工作,如果变通办法是必要的?任何见解或改进建议将不胜感激。谢谢!

bakd9h0s

bakd9h0s1#

简单地说,您在removeNotif回调函数中遇到了一个关于所选notifications状态值的陈旧闭包的问题。换句话说,removeNotif在其生命周期中永远不会看到任何更新的notifications值。
你尝试的解决方法也相当复杂。我相信你可以使用React useCallback钩子来实现一个工作解决方案,将当前notifications状态值重新封装在removeNotif回调处理程序中。

import { useCallback } from 'react';
import { useAppSelector } from "Redux/helpers";
import { selectAgentState } from "Redux/slices/agentSlice";

const useRemoveRoomNotif = () => {
  const { notifications } = useAppSelector(selectAgentState);
  console.log("Outside function:", notifications);

  const removeNotif = useCallback((rid: string, markNotificationsAsRead) => {
    console.log("Inside function:", notifications);
    const ntf = notifications.filter((notif) => notif.roomID === rid && !notif.isRead);
    if (!!ntf.length) markNotificationsAsRead(ntf);
  }, [notifications]);

  return { removeNotif };
};

字符串
如果你的代码没有使用更新的removeNotif回调引用,即它被用作事件侦听器,那么另一种方法是在React ref中“缓存”当前notifications值,并在removeNotif处理程序中引用ref的当前值。
范例:

import { useEffect, useRef } from 'react';
import { useAppSelector } from "Redux/helpers";
import { selectAgentState } from "Redux/slices/agentSlice";

const useRemoveRoomNotif = () => {
  const { notifications } = useAppSelector(selectAgentState);
  const notificationsRef = useRef(notifications);
  console.log("Outside function:", notifications);

  // Cache current notifications value in ref
  useEffect(() => {
    notificationsRef.current = notifications;
  }, [notifications]);

  const removeNotif = useCallback((rid: string, markNotificationsAsRead) => {
    // Get current notifications ref value
    const notifications = notificationsRef.current;

    console.log("Inside function:", notifications);
    const ntf = notifications.filter((notif) => notif.roomID === rid && !notif.isRead);
    if (!!ntf.length) markNotificationsAsRead(ntf);
  }, [notifications]);

  return { removeNotif };
};

相关问题