当前位置: 首页 > 知识库问答 >
问题:

react.js - 在render函数中状态更新了,但在事件函数内部取不到最新状态,如何更改?

卫焕
2024-07-03

在render函数中状态更新了,为何在函数内部中取这个状态时,这个状态不是最新的?

下面使用了selectedKeys状态,我在render和函数内部都打印了,打印的结果可看最后一张图。问题出现在第二次调用,函数里面的selectedKeys不是上一次更新数据

const Notice = () => {
   const [selectedKeys, setSelectedKeys] = useState([]);
   const handleSwipeRight = (id: string) => {
      console.log('selectedKeys-in', selectedKeys);
      const isExist = selectedKeys.find((item) => item === id);
      let newKeys;

      if (isExist) {
         newKeys = selectedKeys.filter((item) => item !== id);
      } else {
         newKeys = [...selectedKeys, id];
      }
      setSelectedKeys([...newKeys]);
   };

   console.log('selectedKeys-out-正常更新', selectedKeys);

   return (
         {list.length === 0
            ? '暂无通知'
            : list.map((item) => {
                 let borderCls = '';
                 if (selectedKeys.includes(item._id)) {
                    borderCls = 'border-red-300';
                 }
                 console.log('selectedKeys', selectedKeys);
                 return (
                    <Card
                       key={item._id}
                       onSwipeRight={handleSwipeRight.bind(this, item)}
                       className={borderCls}
                    >
                       {item.msg}
                    </Card>
                 );
              })}
   );
};

export default Notice;

Card.tsx

import { CustomProps } from '@/types';
import { useTouch } from '@/hooks';

interface ICard extends CustomProps {
   isbadge?: boolean;
   isAnimate?: boolean;
}
const Card: React.FC<ICard> = ({
   children,
   isbadge,
   onSwipeLeft,
   onSwipeRight,
   isAnimate,
   className = '',
   ...rest
}) => {
   const { ref } = useTouch({ onSwipeLeft, onSwipeRight, isAnimate });

   let baseCls =
      'text-sm rounded-md py-1 px-2 bg-white border text-gray-700 relative ' +
      className;

   return (
      <div className={baseCls} ref={ref} {...rest}>
         {isbadge && (
            <div className="w-2 h-2 bg-red-400 rounded-full absolute -right-0.5 -top-0.5"></div>
         )}
         {children}
      </div>
   );
};

export default Card;

useTouch.ts

import { useEffect, useRef } from "react"

type Props = {
    onSwipeRight?: () => void
    onSwipeLeft?: () => void
    isAnimate?: boolean, // 是否加入滑动动画
    threshold?: number
}

// 注册左滑右滑事件
const useTouch = (props: Props) => {
    const ref = useRef<HTMLDivElement>()

    const startX = useRef(0);
    const startY = useRef(0);

    const handleTouchStart = (e) => {
        startX.current = e.touches[0].clientX;
        startY.current = e.touches[0].clientY;
    };
    const handleTouchEnd = (e) => {
        const deltaX = e.changedTouches[0].clientX - startX.current;
        const deltaY = e.changedTouches[0].clientY - startY.current;
        if (Math.abs(deltaX) > Math.abs(deltaY) && deltaX > 0) {
            props.onSwipeRight && props.onSwipeRight()
        } else if (Math.abs(deltaX) > Math.abs(deltaY) && deltaX < 0) {
            props.onSwipeLeft && props.onSwipeLeft()
        }
        if (props.isAnimate) {
            ref.current.style.transition = 'transform 0.3s ease';
            ref.current.style.transform = 'translateX(0)';
        }
    };

    const handleTouchMove = (e) => {
        if (props.isAnimate) {
            const touchEndX = e.touches[0].clientX;
            const deltaX = touchEndX - startX.current;
            const threshold = props.threshold || 16

            if (Math.abs(deltaX) > threshold) {

                ref.current.style.transform = `translateX(${deltaX > 0 ? threshold : -threshold}px)`;
            }

        }
    }

    useEffect(() => {
        const dom = ref.current;
        if (!dom) return
        dom.addEventListener('touchstart', handleTouchStart);
        dom.addEventListener('touchmove', handleTouchMove);
        dom.addEventListener('touchend', handleTouchEnd);

        return () => {
            dom.removeEventListener('touchstart', handleTouchStart);
            dom.removeEventListener('touchmove', handleTouchMove);
            dom.removeEventListener('touchend', handleTouchEnd);
        };
    }, [])
    return {
        ref
    }
}

export default useTouch

打印内容
image.png

共有2个答案

东龙野
2024-07-03

麻了,试了很多种写法,最后这样写正常了。但上面为什么不是最新的状态依旧是个谜

const handleSwipeRight = (id: string) => {
  setSelectedKeys((prev) => {
     if (prev.includes(id)) {
        return prev.filter((key) => key !== id);
     }
     return [...new Set([...prev, id])];
  });
};
穆飞龙
2024-07-03

代码中的 useEffect 只触发了一次,在 useEffect(, [加入依赖]) 就可以

 类似资料:
  • 我正在尝试使用reactjs通过调用axios创建用户配置文件。但我只能在使用Effect时看到更新的状态,而在其他地方看不到。在loginPage中。js,我正在尝试获取entryfirstName、entryLastName和role的最新状态,并将其发布到登录函数中,该函数将返回到我的userProvider.js中。我不知道如何更新状态,所以任何反馈都比我得到的要好。 我是新手反应,我无法

  • 我的Redux状态是如何更新的,可以在pokelist.js文件中注销,但是我的状态变量没有设置好,cardList还是一个空数组,我如何正确设置状态?我注销pokelist.js文件中的集合,它首先注销一个空数组,然后是一个包含元素的数组。

  • 我正在构建一个制表符视图,我不明白为什么useState钩子没有更新我的状态。我肯定这是件容易的事,但我在这里已经被难住了一段时间... 我可以看到onPress函数已启动,如果我注销,则item.label是正确的。但是,即使我硬编码参数,setState也不会更改。

  • 问题内容: 我正在尝试仅更新数组状态中的一个元素,但不确定如何执行此操作。 State 设定状态 如果我想更改标记的第四个元素中的键,该怎么做? 谢谢 问题答案: 重要的一点是,我们不应该直接更改状态数组,而要始终在新数组中进行更改,然后使用setState更新状态值。 如 Doc 建议: 切勿直接更改this.state,将this.state视为不可变。 更新状态数组的基本流程是: 1- 首先

  • 我正在开发一个web应用程序,使用React跟踪水果供应商的库存。js,MongoDB,Node。js和Express。我调用了数据库endpoint来呈现表中的数据。现在,我尝试使用按钮增加和减少库存量,但当我尝试设置新状态时,它不起作用。我尝试通过单击更改状态,然后更新数据库中的新状态。有什么建议吗? > 可结果成分: 从'react'导入Reac,{Component};从“react bo

  • 我正在调用这个函数。因为它在增加值,但是当我访问它时,它返回以前的值。我想访问同一函数中最新更新的值,我应该做什么。 如何访问同一函数中的最新状态值