V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
devzhaoyou
V2EX  ›  React

React hook 使用疑惑

  •  
  •   devzhaoyou ·
    gezhaoyou · 11 天前 · 1939 次点击
    const [count, setCount] = useState(0);
    
    const fetch = () => {
      fetchMoreData(count)
    };
    
    const handleClick = () => {
      // 每次 fecth 前都要重置一下 count
      setCount(0);
      fetch()
    };
    

    这段代码 每次 handleClick 都要重置 count 的值为 0 ,然后使用 fetch 获取数据,fetch 会使用 count 的值; 如果上面的写法的问题是,count 在使用的时候并没有设置为 0

    如果改为 useEffect 方式,如果 count 的值没有变化,又不会触发

    const [count, setCount] = useState(0);
    
    const fetch = () => {
      fetchMoreData(count)
    };
    
    useEffect(() => {
      fetch();
    }, [count]);
    
    const handleClick = () => {
      // count 的值之前就是 0 ,上面的 useEffect 不触发
      setCount(0);
    };
    

    所以,上面的这种情况该如何处理呢? 刚接触 react 感觉很简单的逻辑,在 react 里处理起来好复杂

    第 1 条附言  ·  11 天前
    感谢各位,已通过传值的方式解决。确实应该转变下思想,函数尽量不访问外部状态。
    第 2 条附言  ·  11 天前
    就是为了做 这个站 https://www.picprose.net ,左边这个图片加载列表,练手的。现在还有问题是,输入新关键词之后,滚动条返回不到最顶部,还不知道咋做
    32 条回复    2024-04-25 16:05:11 +08:00
    chanChristin
        1
    chanChristin  
       11 天前
    应该是 useState 不会立即更新的问题,你可以换成 useRef 来确认一下,或者是在各处打印一下 useState 的值看看。
    NessajCN
        2
    NessajCN  
       11 天前
    你没说你需求是啥
    icoming
        3
    icoming  
       11 天前
    这样就行了:

    const fetch = () => {
    fetchMoreData(0)
    };
    withoutxx
        4
    withoutxx  
       11 天前
    这种要看原始需求。。。
    count 不变为什么需要再调用 fetch ,不清楚 fetch 具体逻辑。

    简单点就第一种写法,fetch 直接接收 count 参数就可以。
    xling
        5
    xling  
       11 天前
    跟 react 的 fiber 有关,设置后不会立即更新,可以直接把正确的值传递到你需要的函数
    jguo
        6
    jguo  
       11 天前
    你觉得复杂是因为自己都没有把逻辑理顺。先确定一个根本问题,在什么情况下需要调用 fetchMoreData 。
    cat
        7
    cat  
       11 天前
    修改前的问题:setCount 是异步的,它还没执行完就会执行 fetch 了;
    修改后的问题:count 值没变化,一直都是 0 ,自然就不会再次触发 useEffect ;
    codehz
        8
    codehz  
       11 天前   ❤️ 1
    网络请求建议直接上 swr 吧,你这个看起来是想做类似分页/无限加载+刷新的效果?那么 swr/infinite 里就可以做了,直接 setcount 然后再 revalidate ,不会有任何冲突,也能实现想要的效果。。。
    iOCZS
        9
    iOCZS  
       11 天前
    你这个例子不好,你应该说你有个分页请求,刚进来请求 page=0 ,这时候可以下拉刷新,重新请求 page=0 ;也可以上拉加载 page=1
    devzhaoyou
        10
    devzhaoyou  
    OP
       11 天前
    @iOCZS 是的,现在就是类似的场景
    devzhaoyou
        11
    devzhaoyou  
    OP
       11 天前
    @jguo 是的,想要什么是知道的。就是没有理清逻辑,还想简单点写。感觉思想得变下,还没适应 react.
    devzhaoyou
        12
    devzhaoyou  
    OP
       11 天前
    @codehz 大神啊,是的就是这样的需求
    iOCZS
        13
    iOCZS  
       11 天前
    @devzhaoyou 我的想法是 page 仅做存储,也就是 const page = useRef(0),用实际请求到的数据来刷新页面,const list = useState([])。
    wuyiccc
        14
    wuyiccc  
       11 天前
    react 中 useState 是异步更新的
    gaoryrt
        15
    gaoryrt  
       11 天前
    const fetch = useCallback(() => {
    fetchMoreData(count)
    }, [count])

    这样行不行
    wuyiccc
        16
    wuyiccc  
       11 天前
    既然已经确认 cout 为 0 了,就不要通过 state 去获取了,直接传递函数参数 count=0 吧
    evada
        17
    evada  
       11 天前
    我觉得 4 楼没问题,可以把 count 当参数传递
    santree
        18
    santree  
       11 天前
    导致你这个问题的原因是因为在 React 里,setState 都会默认经过收集和批处理的流程,简单来说他不是立即生效的。

    为了处理这个问题,如果你的 count 是一个和渲染相关的值,而且你必须要在 handleClick 时强行进行一次重置为 0 并请求最新值进行设置(也就是说界面上必须反映出这个 count -> 0 -> newCount )我的建议是使用 flushSync 这个 api 对状态设置进行包裹,强制同步更新一次状态。

    like this:
    ```typescript
    import { flushSync } from 'react-dom';

    flushSync(() => {
    setCount(0);
    });
    ```
    具体可以查看文档: https://react.dev/reference/react-dom/flushSync
    santree
        19
    santree  
       11 天前
    看之前的回复感觉你更需要把需求理清楚一点,避免这种状态的设置更好。
    cookygg
        20
    cookygg  
       11 天前
    const [count, setCount] = useState(0);

    const [,update] = useState({})

    const fetch = () => {
    fetchMoreData(count)
    };

    useEffect(() => {
    fetch();
    }, [count]);

    const handleClick = () => {
    // count 的值之前就是 0 ,上面的 useEffect 不触发
    setCount(0);

    // 手动更新 也算一个解决
    update({})
    };
    devzhaoyou
        21
    devzhaoyou  
    OP
       11 天前
    感谢各位,已理清,确实应该通过传值的方式来解决,函数应该尽量不访问外部 state ,有点函数式编程的思想。
    同时也确定了一个事情,react 确实不太好做 set 后立刻 get 操作
    另外编程思想真得变一变
    devzhaoyou
        22
    devzhaoyou  
    OP
       11 天前
    @wuyiccc #16 是的,正确的路子
    mwjz
        23
    mwjz  
       11 天前
    封装一个 hooks , 既有 useState 也有 useRef , 不过还是建议用 ahook 的 useRequest
    june4
        24
    june4  
       11 天前
    左转 solid-js ,可以 set 后马上 get, 最主要的是,视图函数只运行一次,再也没有这些操蛋的规则
    zmaplex
        26
    zmaplex  
       11 天前
    import { useState } from 'react';
    import useSWR from 'swr';

    const fetchMoreData = async (count: number) => {
    await new Promise((resolve) => setTimeout(resolve, count * 100));
    return count
    }

    export default function Demo() {
    const [count, setCount] = useState(0);
    const { data, error, isLoading } = useSWR(`count-${count}-swr`, async () => {
    if (count == 5) {
    throw new Error("count is 5")
    }
    return await fetchMoreData(count)
    })

    const handleClick = () => {
    setCount(0);
    };

    if (isLoading) return <div>Loading...</div>
    if (error) return <div>{`${error}`}</div>

    return (<div >
    <div>{data}</div>

    <button onClick={() => setCount(count + 1)}>+</button>

    <button onClick={handleClick}>handleClick</button>
    </div>)

    }
    mrwangjustsay
        27
    mrwangjustsay  
       11 天前
    想研究的深一点可以参考: https://github.com/MrWangJustToDo/MyReact
    realJamespond
        28
    realJamespond  
       11 天前
    加个方法 fetchAndCount(count) 包起来用
    yqcode
        29
    yqcode  
       11 天前
    @devzhaoyou #21 react 确实不太好做 set 后立刻 get 操作,这只是 setState 的特性而已,如果你要始终记录一个值,你可以考虑用 useRef
    uni
        30
    uni  
       10 天前
    我最喜欢 react 的地方就是它一直在强制使用者用函数式的思维去思考,作为一个被各种各样的副作用强 x 多年的函数式信仰者,我总有一种大仇得报的快感
    jackge0323
        31
    jackge0323  
       10 天前
    useState(() => 0)应该就可以解决了吧,使用 useState 的初始化函数。
    magicdawn
        32
    magicdawn  
       10 天前 via Android
    你需要一个好用的 useState hook:useRefState, 参见 https://github.com/alibaba/hooks/pull/2348#issuecomment-1794002832 , 是增加了同步支持的 ahooks.useGetState 版本,或者用 react-use.useGetSet
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   882 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 195ms · UTC 22:49 · PVG 06:49 · LAX 15:49 · JFK 18:49
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.