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

React hook 使用疑惑

  •  
  •   devzhaoyou 2024-04-24 14:16:56 +08:00 3591 次点击
    这是一个创建于 534 天前的主题,其中的信息可能已经有所发展或是发生改变。
    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 条附言    2024-04-24 15:58:17 +08:00
    感谢各位,已通过传值的方式解决。确实应该转变下思想,函数尽量不访问外部状态。
    第 2 条附言    2024-04-24 16:06:53 +08:00
    就是为了做 这个站 https://www.picprose.net ,左边这个图片加载列表,练手的。现在还有问题是,输入新关键词之后,滚动条返回不到最顶部,还不知道咋做
    32 条回复    2024-04-25 16:05:11 +08:00
    Leeeeex
        1
    Leeeeex  
    PRO
       2024-04-24 14:20:19 +08:00
    应该是 useState 不会立即更新的问题,你可以换成 useRef 来确认一下,或者是在各处打印一下 useState 的值看看。
    NessajCN
        2
    NessajCN  
       2024-04-24 14:22:16 +08:00
    你没说你需求是啥
    icoming
        3
    icoming  
       2024-04-24 14:24:54 +08:00
    这样就行了:

    const fetch = () => {
    fetchMoreData(0)
    };
    withoutxx
        4
    withoutxx  
       2024-04-24 14:25:26 +08:00
    这种要看原始需求。。。
    count 不变为什么需要再调用 fetch ,不清楚 fetch 具体逻辑。

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

    这样行不行
    wuyiccc
        16
    wuyiccc  
       2024-04-24 14:39:29 +08:00
    既然已经确认 cout 为 0 了,就不要通过 state 去获取了,直接传递函数参数 count=0 吧
    evada
        17
    evada  
       2024-04-24 14:51:18 +08:00
    我觉得 4 楼没问题,可以把 count 当参数传递
    santree
        18
    santree  
       2024-04-24 15:35:12 +08:00
    导致你这个问题的原因是因为在 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  
       2024-04-24 15:37:27 +08:00
    看之前的回复感觉你更需要把需求理清楚一点,避免这种状态的设置更好。
    benjim
        20
    benjim  
       2024-04-24 15:51:28 +08:00
    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
       2024-04-24 15:56:02 +08:00
    感谢各位,已理清,确实应该通过传值的方式来解决,函数应该尽量不访问外部 state ,有点函数式编程的思想。
    同时也确定了一个事情,react 确实不太好做 set 后立刻 get 操作
    另外编程思想真得变一变
    devzhaoyou
        22
    devzhaoyou  
    OP
       2024-04-24 15:57:01 +08:00
    @wuyiccc #16 是的,正确的路子
    mwjz
        23
    mwjz  
       2024-04-24 16:19:45 +08:00
    封装一个 hooks , 既有 useState 也有 useRef , 不过还是建议用 ahook 的 useRequest
    june4
        24
    june4  
       2024-04-24 16:29:56 +08:00
    左转 solid-js ,可以 set 后马上 get, 最主要的是,视图函数只运行一次,再也没有这些操蛋的规则
    huangzhiyia
        25
    huangzhiyia  
       2024-04-24 17:55:25 +08:00
    huangzhiyia
        26
    huangzhiyia  
       2024-04-24 18:01:25 +08:00
    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  
       2024-04-24 18:15:57 +08:00
    想研究的深一点可以参考: https://github.com/MrWangJustToDo/MyReact
    realJamespond
        28
    realJamespond  
       2024-04-24 18:17:56 +08:00
    加个方法 fetchAndCount(count) 包起来用
    yqcode
        29
    yqcode  
       2024-04-24 20:19:38 +08:00
    @devzhaoyou #21 react 确实不太好做 set 后立刻 get 操作,这只是 setState 的特性而已,如果你要始终记录一个值,你可以考虑用 useRef
    uni
        30
    uni  
       2024-04-25 14:38:31 +08:00
    我最喜欢 react 的地方就是它一直在强制使用者用函数式的思维去思考,作为一个被各种各样的副作用强 x 多年的函数式信仰者,我总有一种大仇得报的快感
    jackge0323
        31
    jackge0323  
       2024-04-25 15:33:51 +08:00
    useState(() => 0)应该就可以解决了吧,使用 useState 的初始化函数。
    magicdawn
        32
    magicdawn  
       2024-04-25 16:05:11 +08:00 via Android
    你需要一个好用的 useState hook:useRefState, 参见 https://github.com/alibaba/hooks/pull/2348#issuecomment-1794002832 , 是增加了同步支持的 ahooks.useGetState 版本,或者用 react-use.useGetSet
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     978 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 31ms UTC 19:14 PVG 03:14 LAX 12:14 JFK 15:14
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86