React-Native中Pressable onPress无法获取最新useState状态求助
问题分析
你遇到的确实是React闭包陷阱导致的问题:handleAddTransaction函数在组件初始渲染时创建,捕获了当时的name和amount状态值;后续状态更新触发组件重新渲染时,虽然会生成新的handleAddTransaction函数,但如果Pressable组件没有正确更新它的onPress回调绑定,点击时就会调用旧的函数,从而读取到旧的状态值——而输入框因为直接绑定了最新的state,所以显示正常。
解决方案
下面是几种可行的解决方法:
方法1:用useCallback包裹回调函数
通过useCallback将handleAddTransaction与name、amount绑定,确保状态更新时生成新的回调函数,让Pressable能获取到最新的版本:
import { useCallback } from 'react'; const ManualTransactionPage = ({ tabId }: {tabId: string}) => { const [name, setName] = useState<string>("Kfc"); const [amount, setAmount] = useState<string>("15"); useEffect(() => { console.log("state", { title: name, amount, }); }, [name, amount]); // 用useCallback包裹,依赖项包含state const handleAddTransaction = useCallback(() => { console.log("state", { title: name, amount, }); }, [name, amount]); // 依赖name和amount,状态更新时重新生成函数 return ( <View className="pt-5 mx-3"> <TextInput className="w-full bg-white rounded-xl text-2xl mb-4 px-3 py-4" value={name} onChangeText={setName} placeholder="KFC" /> <TextInput className="w-full bg-white rounded-xl text-2xl mb-4 px-3 py-4" value={amount} onChangeText={setAmount} placeholder="9.99" /> <Pressable onPress={handleAddTransaction} className="flex flex-row justify-center mt-5 group" > <ButtonStyling> <Text className="text-white text-xl px-3">Add</Text> </ButtonStyling> </Pressable> </View> ); };
方法2:用useRef保存最新状态
将状态值存入ref,确保回调能直接读取到最新的引用值:
import { useRef } from 'react'; const ManualTransactionPage = ({ tabId }: {tabId: string}) => { const [name, setName] = useState<string>("Kfc"); const [amount, setAmount] = useState<string>("15"); // 创建ref保存最新状态 const latestState = useRef({ name, amount }); // 状态更新时同步ref的值 useEffect(() => { latestState.current = { name, amount }; console.log("state", { title: name, amount, }); }, [name, amount]); const handleAddTransaction = () => { // 直接读取ref的当前值 console.log("state", latestState.current); }; return ( <View className="pt-5 mx-3"> <TextInput className="w-full bg-white rounded-xl text-2xl mb-4 px-3 py-4" value={name} onChangeText={setName} placeholder="KFC" /> <TextInput className="w-full bg-white rounded-xl text-2xl mb-4 px-3 py-4" value={amount} onChangeText={setAmount} placeholder="9.99" /> <Pressable onPress={handleAddTransaction} className="flex flex-row justify-center mt-5 group" > <ButtonStyling> <Text className="text-white text-xl px-3">Add</Text> </ButtonStyling> </Pressable> </View> ); };
方法3:直接在onPress中内联逻辑
跳过单独的回调函数,直接在Pressable的onPress里写逻辑,这样每次渲染都会绑定最新的状态:
const ManualTransactionPage = ({ tabId }: {tabId: string}) => { const [name, setName] = useState<string>("Kfc"); const [amount, setAmount] = useState<string>("15"); useEffect(() => { console.log("state", { title: name, amount, }); }, [name, amount]); return ( <View className="pt-5 mx-3"> <TextInput className="w-full bg-white rounded-xl text-2xl mb-4 px-3 py-4" value={name} onChangeText={setName} placeholder="KFC" /> <TextInput className="w-full bg-white rounded-xl text-2xl mb-4 px-3 py-4" value={amount} onChangeText={setAmount} placeholder="9.99" /> <Pressable onPress={() => { console.log("state", { title: name, amount, }); }} className="flex flex-row justify-center mt-5 group" > <ButtonStyling> <Text className="text-white text-xl px-3">Add</Text> </ButtonStyling> </Pressable> </View> ); };
验证说明
这几种方法都能解决闭包导致的旧状态读取问题,你可以根据自己的代码习惯选择。其中useCallback是最符合React Hooks规范的方式,能保证回调函数仅在依赖项变化时更新;useRef适合需要在多个地方读取最新状态的场景;内联逻辑则是最简单直接的写法。
内容的提问来源于stack exchange,提问作者Gavin How
相关产品推荐
相关产品推荐

