关于 useState 是异步执行

本文探讨了React中useState和useRef的区别,强调了useState的异步执行导致的状态像快照,以及如何通过useEffect和useMemo确保获取最新值。同时介绍了useImmer在处理流动边框动画时的状态管理。
摘要由CSDN通过智能技术生成
前言

上一篇在玩 流动边框 的时候,发现 useState 更新变量之后不能获取到最新的值,而采用 useRef 去存储变量。

在查略了一些资料关于 useState 和 useRef 的区别之后,依旧有些不理解,遂向比我厉害的人请教了下,于是有了这篇的记录。


正文

setCount 之后打印的 count 值依旧是 0,是由于 useState 异步执行而 状态的行为像快照

import { useEffect, useState } from 'react';

export default function Test() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log(1, count);
    setCount(1);
    console.log(2, count);
  }, []);
}

想看最新的值,要么将 console.log(count) 放在 useEffect 之外,要么将 count 作为 useEffect 的依赖项,即

import { useEffect, useState } from 'react';

export default function Test() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    setCount(1);
  }, []);

  useEffect(() => {
    console.log(count);
  }, [count]);
}

类组件写法:this.setState 的第二个参数接收一个回调函数,可以通过它获取最新的值。

再回归 流动边框

'use client';

import { useEffect, useMemo } from 'react';
import { useImmer } from 'use-immer';
import styles from './styles.module.css';

export default function Effect() {
  const [pos, updatePos] = useImmer({ x: 0, y: 50 });
  const [done, setDone] = useImmer(false);
  const background = useMemo(() => {
    return `radial-gradient(20% 40% at ${pos.x}% ${pos.y}%, red 0%, transparent 100%)`;
  }, [pos]);

  function move() {
    const { x, y } = pos;
    if (x >= 0 && x < 50 && y <= 50 && y > 0) {
      updatePos({ x: x + 1, y: y - 1 }); // 50 0
    } else if (x >= 50 && x < 100 && y >= 0 && y < 50) {
      updatePos({ x: x + 1, y: y + 1 }); // 100 50
    } else if (x <= 100 && x > 50 && y >= 50 && y < 100) {
      updatePos({ x: x - 1, y: y + 1 }); // 50 100
    } else if (x <= 50 && x > 0 && y <= 100 && y > 50) {
      updatePos({ x: x - 1, y: y - 1 }); // 0 50
    }
  }

  useEffect(() => {
    if (!done) requestAnimationFrame(move);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [pos, done]);

  return (
    <div className={styles.button}>
      <button>CLICK</button>
      <span style={{ background }}></span>
    </div>
  );
}

  • 10
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值