React Native状态更新问题求助:点击按钮后getData内状态未更新
React Native中setState后立即调用函数无法获取更新状态的问题解决
问题原因
React的useState状态更新是异步批量执行的,当你在handleSubmitBtn中调用setSearchBool(true)和setFirstTimeSearch(true)后,组件并不会立刻更新状态,当前函数调用栈内的getData仍然会捕获更新前的旧状态值,所以在getData里打印的还是初始的false。而普通let变量是同步赋值,当前作用域内可以直接拿到最新值,所以不会有这个问题。
解决方案
方案1:直接传递参数给getData
既然状态更新是异步的,不如把需要的状态值直接作为参数传给getData,跳过依赖组件状态的步骤:
import { View, TextInput } from 'react-native' import React, { useState } from 'react' const SearchScreen = ({ navigation }) => { const [searchText, setSearchText] = useState(""); const [clicked, setClicked] = useState(false); const [page, setPage] = useState(1); const [isSearchBool, setSearchBool] = useState(false); const [isFirstTimeSearch, setFirstTimeSearch] = useState(false); const [loading, setLoading] = useState(false); const [isListEnd, setIsListEnd] = useState(false); const handleSubmitBtn = () => { const newSearchBool = true; const newFirstTime = true; setSearchBool(newSearchBool); setFirstTimeSearch(newFirstTime); getData(newSearchBool, newFirstTime); } const getData = async (currentSearchBool, currentFirstTime) => { if (!loading && !isListEnd) { console.log('getData'); setLoading(true); const BASE_URL = "https://api.unsplash.com" console.log(`set search boolean to: ${currentSearchBool}`); console.log(`set First search boolean to: ${currentFirstTime}`); if(currentSearchBool && currentFirstTime){ console.log("Set Page Number to 1"); setPage(1); } console.log(page); } }; return ( <View style={{ flex: 1, }}> <TextInput onSubmitEditing={handleSubmitBtn} onChangeText={setSearchText} value={searchText} placeholder="Search Photos, collections" onFocus={() => setClicked(true)} /> </View> ) } export default SearchScreen;
方案2:用useEffect监听状态变化
如果必须依赖组件状态来触发getData,可以通过useEffect监听isSearchBool和isFirstTimeSearch的变化,当它们变为true时自动执行getData:
import { View, TextInput } from 'react-native' import React, { useState, useEffect } from 'react' const SearchScreen = ({ navigation }) => { const [searchText, setSearchText] = useState(""); const [clicked, setClicked] = useState(false); const [page, setPage] = useState(1); const [isSearchBool, setSearchBool] = useState(false); const [isFirstTimeSearch, setFirstTimeSearch] = useState(false); const [loading, setLoading] = useState(false); const [isListEnd, setIsListEnd] = useState(false); const handleSubmitBtn = () => { setSearchBool(true); setFirstTimeSearch(true); } const getData = async () => { if (!loading && !isListEnd) { console.log('getData'); setLoading(true); const BASE_URL = "https://api.unsplash.com" console.log(`set search boolean to: ${isSearchBool}`); console.log(`set First search boolean to: ${isFirstTimeSearch}`); if(isSearchBool && isFirstTimeSearch){ console.log("Set Page Number to 1"); setPage(1); } console.log(page); } }; useEffect(() => { if (isSearchBool && isFirstTimeSearch) { getData(); // 若只需触发一次,可在此重置状态避免重复调用 // setFirstTimeSearch(false); } }, [isSearchBool, isFirstTimeSearch, loading, isListEnd]); return ( <View style={{ flex: 1, }}> <TextInput onSubmitEditing={handleSubmitBtn} onChangeText={setSearchText} value={searchText} placeholder="Search Photos, collections" onFocus={() => setClicked(true)} /> </View> ) } export default SearchScreen;
注意事项
- 方案1更直接,适合需要立即执行函数的场景,规避异步状态更新带来的闭包问题。
- 方案2适合根据状态变化自动触发逻辑的场景,需注意添加合适的依赖项,必要时用
useCallback包裹getData避免无效渲染。
内容的提问来源于stack exchange,提问作者Piyush Kumar
相关产品推荐
相关产品推荐

