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

函数式组件中,函数内多重调用如何获取最新的 state 值?

  •  
  •   s609926202 ·
    shangdev · 2023-06-26 13:56:57 +08:00 · 1755 次点击
    这是一个创建于 551 天前的主题,其中的信息可能已经有所发展或是发生改变。

    react 函数式组件中,在 func1 函数内调用 func2 ,func2 更新 messages 后,再调用 func2 ,此时 func2 内打印的 messages 值还是个初始值?

    场景是使用 openai function call 的时候。

    代码如下:

    export default function xx(props) {
      const { messages, appendMsg } = useMessages(initialMessages);
    
      function func1() {
        func2();
      }
    
      function func2() {
        console.log(messages);
        appendMsg({xx});
        appendMsg({yy});
        func2();
      }
      
      return (
        <button onClick={func1}>Call func1</button>
      );
    }
    
    第 1 条附言  ·  2023-06-26 14:54:56 +08:00

    用useRef获取了最新的state值:

    const messagesRef = useRef(messages);
    
    useEffect(() => {
        messagesRef.current = messages;
    }, [messages]);
    
    18 条回复    2023-08-10 08:48:04 +08:00
    enchilada2020
        1
    enchilada2020  
       2023-06-26 14:08:35 +08:00 via Android
    你这不无限递归了吗
    ewiglicht
        2
    ewiglicht  
       2023-06-26 14:11:14 +08:00
    daydreamcafe
        3
    daydreamcafe  
       2023-06-26 14:16:35 +08:00
    2 楼的文档已经很完整的解释了原理,关于你这个场景,使用回调函数的方式去更新状态可以保证每次的 state 为最新

    appendMsg((prevState) => {
    // ... 在这里做一些状态的改变,之后 return 出想要修改的状态,记得读取的状态要来自 prevState
    })
    leroy20317
        4
    leroy20317  
       2023-06-26 14:19:49 +08:00   ❤️ 1
    useRef
    s609926202
        5
    s609926202  
    OP
       2023-06-26 14:21:16 +08:00
    @enchilada2020 #1 openai funtion calling 就是递归吧,只有匹配到 function ,就递归
    296727
        6
    296727  
       2023-06-26 14:24:09 +08:00   ❤️ 1
    s609926202
        7
    s609926202  
    OP
       2023-06-26 14:28:21 +08:00
    @daydreamcafe #3 appendMsg 是第三方库( chatUI )导出的一个方法,只接收新的 msg 对象,貌似做不了回调函数这样的调用。
    Leviathann
        8
    Leviathann  
       2023-06-26 15:15:00 +08:00
    message 这个值或者引用是栈上变量,每次重新渲染,函数重新被调用,它的调用栈帧都是新的,也就是说旧的变量一旦捕获就不会随着组件的重新渲染而变更

    解决方法就是把它的值放在堆上,用一个不变的引用关系去指向它,在 react 里,这是 ref
    Leviathann
        9
    Leviathann  
       2023-06-26 15:17:16 +08:00
    另外传入 useEffect 的 callback 是在渲染完成后执行,本意也并不是用来 watch ,你是否需要这个延迟?
    s609926202
        10
    s609926202  
    OP
       2023-06-26 15:41:19 +08:00
    @Leviathann #9 没懂,哪里加延迟?是 useEffect 里加延迟吗。
    oppt
        11
    oppt  
       2023-06-26 17:41:59 +08:00
    把 message 作为参数传进 fun2
    function func2(messages) {
    console.log(messages);
    const newMessages = {xx}
    appendMsg(newMessages);
    func2(newMessages);
    }
    s609926202
        12
    s609926202  
    OP
       2023-06-26 17:43:52 +08:00
    @oppt #11 靠传递参数是不行的
    amlee
        13
    amlee  
       2023-06-27 23:23:38 +08:00
    不对啊,楼上这么多回答的,你们都清楚 op 代码中的 useMessages 是一个什么样的 hook ?
    magicdawn
        14
    magicdawn  
       2023-07-04 14:36:38 +08:00 via Android
    用 useMomoizedFn 以前叫 usePersistFn, 也是社区流产的 useEvent 或 useEventCallback
    s609926202
        15
    s609926202  
    OP
       2023-07-04 15:36:24 +08:00
    @magicdawn #14 这个也是 ahook 中提供的,为了减少引用库的数量,用 ref 处理了。
    KgM4gLtF0shViDH3
        16
    KgM4gLtF0shViDH3  
       2023-08-08 18:05:55 +08:00
    @ewiglicht 你是怎么发现官方的中文文档的,没找到任何切换语言的地方。
    ewiglicht
        17
    ewiglicht  
       2023-08-09 09:39:09 +08:00
    @bestkayle 谷歌搜索
    KgM4gLtF0shViDH3
        18
    KgM4gLtF0shViDH3  
       2023-08-10 08:48:04 +08:00
    @ewiglicht 还真有,我用英文搜就搜不到。。。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2280 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 01:49 · PVG 09:49 · LAX 17:49 · JFK 20:49
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.