提交表单时如何等待onBlur状态更新
How to wait for onBlur state update when submitting form
我在 ScrollView 中有一个大表单,其中 keyBoardShouldPersistTaps 设置为“已处理”,并且正在保存在 TextInput 中调用 onBlur 时输入到全局状态的值(onChangeText 保存到每个组件中的本地状态以性能更高)。
当我的用户提交表单时出现问题,如果他们点击提交按钮,同时仍然有一个文本输入(其中有值),提交调用是 运行 而没有来自按下提交按钮时聚焦的文本输入。
所有其他文本输入中的所有其他值都已正确提交,因为状态有时间正确更新。
如何确保在调用提交函数之前更新 onBlur 和 useState(我知道这是异步的)?
解释我的挑战的简化代码 (expo snack):
import * as React from 'react';
import { ScrollView, StyleSheet, Button, Alert, TextInput, Keyboard } from 'react-native';
import Constants from 'expo-constants';
export default function App() {
const [globalValue, setGlobalValue] = React.useState('Useless Placeholder');
const [localValue, setLocalValue] = React.useState(globalValue);
return (
<ScrollView keyboardShouldPersistTaps={"handled"} style={styles.container}>
<TextInput
style={{ height: 40, borderColor: 'gray', borderWidth: 1 }}
onChangeText={text => setLocalValue(text)}
value={localValue}
onBlur={() => setGlobalValue(localValue)}
/>
<Button
title="Press me"
onPress={() => {Keyboard.dismiss(); Alert.alert(globalValue);}}
/>
</ScrollView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
});
重现我的问题的步骤:
- 在文本输入中输入内容
- 直接点击提交按钮
- 您将看不到在文本输入中输入的内容,因为提交在状态从 onBlur 更新之前触发
重现有效“提交”的步骤:
- 在文本输入中输入内容
- 点击其他任何地方关闭键盘
- 点击按钮,您将看到您在文本输入中输入的内容
旧代码: 你不能像下面那样做,或者你必须使用另一个名为 'text' 的状态变量吗?
export default function App() {
const placeHolder = "Useless Placeholder";
const [value, onChangeText] = React.useState(placeHolder);
return (
<ScrollView keyboardShouldPersistTaps={"handled"} style={styles.container}>
<TextInput
style={{ height: 40, borderColor: 'gray', borderWidth: 1 }}
onChangeText={text => onChangeText(text)}
value={value}
onBlur={() => {
onChangeText(value || placeHolder);
}}
/>
<Button
title="Press me"
onPress={() => {Keyboard.dismiss(); Alert.alert(value);}}
/>
</ScrollView>
);
}
更新代码:这是我目前能看到的唯一方法
export default function App() {
const placeHolder = 'Useless Placeholder';
const [globalValue, setGlobalValue] = React.useState(placeHolder);
const [localValue, setLocalValue] = React.useState(globalValue);
useEffect(() => {
Keyboard.dismiss();
if(placeHolder !== globalValue) {
Alert.alert(globalValue);
}
}, [globalValue]);
return (
<ScrollView keyboardShouldPersistTaps={"handled"} style={styles.container}>
<TextInput
style={{ height: 40, borderColor: 'gray', borderWidth: 1 }}
onChangeText={text => setLocalValue(text)}
value={localValue}
/>
<Button
title="Press me"
onPress={() => {setGlobalValue(localValue)}}
/>
</ScrollView>
);
}
我在 ScrollView 中有一个大表单,其中 keyBoardShouldPersistTaps 设置为“已处理”,并且正在保存在 TextInput 中调用 onBlur 时输入到全局状态的值(onChangeText 保存到每个组件中的本地状态以性能更高)。
当我的用户提交表单时出现问题,如果他们点击提交按钮,同时仍然有一个文本输入(其中有值),提交调用是 运行 而没有来自按下提交按钮时聚焦的文本输入。
所有其他文本输入中的所有其他值都已正确提交,因为状态有时间正确更新。
如何确保在调用提交函数之前更新 onBlur 和 useState(我知道这是异步的)?
解释我的挑战的简化代码 (expo snack):
import * as React from 'react';
import { ScrollView, StyleSheet, Button, Alert, TextInput, Keyboard } from 'react-native';
import Constants from 'expo-constants';
export default function App() {
const [globalValue, setGlobalValue] = React.useState('Useless Placeholder');
const [localValue, setLocalValue] = React.useState(globalValue);
return (
<ScrollView keyboardShouldPersistTaps={"handled"} style={styles.container}>
<TextInput
style={{ height: 40, borderColor: 'gray', borderWidth: 1 }}
onChangeText={text => setLocalValue(text)}
value={localValue}
onBlur={() => setGlobalValue(localValue)}
/>
<Button
title="Press me"
onPress={() => {Keyboard.dismiss(); Alert.alert(globalValue);}}
/>
</ScrollView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
});
重现我的问题的步骤:
- 在文本输入中输入内容
- 直接点击提交按钮
- 您将看不到在文本输入中输入的内容,因为提交在状态从 onBlur 更新之前触发
重现有效“提交”的步骤:
- 在文本输入中输入内容
- 点击其他任何地方关闭键盘
- 点击按钮,您将看到您在文本输入中输入的内容
旧代码: 你不能像下面那样做,或者你必须使用另一个名为 'text' 的状态变量吗?
export default function App() {
const placeHolder = "Useless Placeholder";
const [value, onChangeText] = React.useState(placeHolder);
return (
<ScrollView keyboardShouldPersistTaps={"handled"} style={styles.container}>
<TextInput
style={{ height: 40, borderColor: 'gray', borderWidth: 1 }}
onChangeText={text => onChangeText(text)}
value={value}
onBlur={() => {
onChangeText(value || placeHolder);
}}
/>
<Button
title="Press me"
onPress={() => {Keyboard.dismiss(); Alert.alert(value);}}
/>
</ScrollView>
);
}
更新代码:这是我目前能看到的唯一方法
export default function App() {
const placeHolder = 'Useless Placeholder';
const [globalValue, setGlobalValue] = React.useState(placeHolder);
const [localValue, setLocalValue] = React.useState(globalValue);
useEffect(() => {
Keyboard.dismiss();
if(placeHolder !== globalValue) {
Alert.alert(globalValue);
}
}, [globalValue]);
return (
<ScrollView keyboardShouldPersistTaps={"handled"} style={styles.container}>
<TextInput
style={{ height: 40, borderColor: 'gray', borderWidth: 1 }}
onChangeText={text => setLocalValue(text)}
value={localValue}
/>
<Button
title="Press me"
onPress={() => {setGlobalValue(localValue)}}
/>
</ScrollView>
);
}