运行一次查询后按钮禁用
Posted
技术标签:
【中文标题】运行一次查询后按钮禁用【英文标题】:Button Disables After Running Query Once 【发布时间】:2020-09-18 01:35:26 【问题描述】:我有一个用户输入电话号码的屏幕。我根据输入运行graphql查询loadUsers
,然后通过showUsers
函数显示搜索结果。它第一次运行良好。我得到结果。但是,在此之后,当有条件地呈现结果时,搜索按钮将变为禁用状态。所以如果我想输入一个不同的电话号码并再次点击搜索按钮,我不能这样做。除非我退出屏幕然后回来。我怎样才能解决这个问题?
我的代码如下所示:
export const AddContactTry: React.FunctionComponent = () =>
const initialValues: FormValues =
phoneNumber: '',
;
const [isSubmitted, setIsSubmitted] = useState(false);
const [userData, setUserData] = useState<UsersLazyQueryHookResult>('');
const navigation = useNavigation();
const validationSchema = phoneNumberValidationSchema;
const [
createUserRelationMutation,
data: addingContactData,
loading: addingContactLoading,
error: addingContactError,
called: isMutationCalled,
,
] = useCreateUserRelationMutation(
onCompleted: () =>
Alert.alert('Contact Added');
,
);
const showUsers = React.useCallback(
(data: UsersLazyQueryHookResult) =>
if (data)
return (
<View style=styles.users>
data.users.nodes.map(
(item: firstName: string; lastName: string; id: number ) =>
const userName = item.firstName
.concat(' ')
.concat(item.lastName);
return (
<View style=styles.item key=item.id>
<Thumbnail
style=styles.thumbnail
source=
uri:
'https://cdn4.iconfinder.com/data/icons/avatars-xmas-giveaway/128/afro_woman_female_person-512.png',
></Thumbnail>
<Text style=styles.userName>userName</Text>
<View style=styles.addButtonContainer>
<Button
rounded
style=styles.addButton
onPress=() =>
addContact(Number(item.id));
setIsSubmitted(false);
setUserData(null);
>
<Icon
name="plus"
size=moderateScale(20)
color="black"
/>
</Button>
</View>
</View>
);
,
)
</View>
);
,
[createUserRelationMutation, userData],
);
const addContact = React.useCallback(
(id: Number) =>
console.log('Whats the Id', id);
createUserRelationMutation(
variables:
input: relatedUserId: id, type: RelationType.Contact, userId: 30 ,
,
);
,
[createUserRelationMutation],
);
const getContactId = React.useCallback(
(data: UsersLazyQueryHookResult) =>
if (data)
if (data.users.nodes.length == 0)
Alert.alert('No User Found');
else
setUserData(data);
,
[addContact],
);
const [loadUsers] = useUsersLazyQuery(
onCompleted: getContactId,
onError: _onLoadUserError,
);
const handleSubmitForm = React.useCallback(
(values: FormValues, helpers: FormikHelpers<FormValues>) =>
setIsSubmitted(true);
const plusSign = '+';
const newPhoneNumber = plusSign.concat(values.phoneNumber);
loadUsers(
variables:
where: phoneNumber: newPhoneNumber ,
,
);
values.phoneNumber = '';
,
[loadUsers],
);
return (
<SafeAreaView>
<View style=styles.container>
<View style=styles.searchTopContainer>
<View style=styles.searchTopTextContainer>
</View>
<View>
<Formik
initialValues=initialValues
onSubmit=handleSubmitForm
validationSchema=validationSchema
>
( handleChange, handleBlur, handleSubmit, values, isValid, dirty ) => (
<View style=styles.searchFieldContainer>
<View style=styles.form>
<FieldInput style=styles.fieldInput
handleChange=handleChange
handleBlur=handleBlur
value=values.phoneNumber
fieldType="phoneNumber"
icon="phone"
placeholderText="49152901820"
/>
<ErrorMessage
name="phoneNumber"
render=(msg) => (
<Text style=styles.errorText>msg</Text>
)
/>
</View>
<View style=styles.buttonContainer>
<Text>Abbrechen</Text>
</Button>
<Button
block
success
disabled=!isValid || !dirty
onPress=handleSubmit
style=styles.button>
<Text>Speichern</Text>
</Button>
</View>
</View>
)
</Formik>
</View>
isSubmitted && showUsers(userData)
</View>
</View>
</SafeAreaView>
);
;
编辑:
按照 cmets 中的建议,我尝试使用 useFormik 代替并将 showUsers 移动到单独的组件,但它也不起作用。首次查询后,该按钮仍会被禁用。
export const AddContactTry: React.FunctionComponent = () =>
const validationSchema = phoneNumberValidationSchema;
const values, handleChange, handleSubmit, dirty, handleBlur, isValid, resetForm, isSubmitting, setSubmitting, touched= useFormik(
initialValues:
phoneNumber: '',
,
//isInitialValid:false,
validationSchema,
onSubmit: (values: FormValues) =>
handleSubmitForm(values);
,
);
console.log('isDirty', dirty);
console.log('isValid', isValid);
console.log('phone numm', values.phoneNumber);
console.log('submitting status', isSubmitting);
const [isSubmitted, setIsSubmitted] = useState(false);
const [userData, setUserData] = useState<UsersLazyQueryHookResult>('');
const navigation = useNavigation();
const _onLoadUserError = React.useCallback((error: ApolloError) =>
Alert.alert('Oops, try again later');
, []);
// const [
// createUserRelationMutation,
//
// data: addingContactData,
// loading: addingContactLoading,
// error: addingContactError,
// called: isMutationCalled,
// ,
// ] = useCreateUserRelationMutation(
// onCompleted: () =>
// Alert.alert('Contact Added');
// ,
// );
// const showUsers = React.useCallback(
// (data: UsersLazyQueryHookResult) =>
// if (data)
// return (
// <View style=styles.users>
// data.users.nodes.map(
// (item: firstName: string; lastName: string; id: number ) =>
// const userName = item.firstName
// .concat(' ')
// .concat(item.lastName);
// return (
// <View style=styles.item key=item.id>
// <Thumbnail
// style=styles.thumbnail
// source=
// uri:
// 'https://cdn4.iconfinder.com/data/icons/avatars-xmas-giveaway/128/afro_woman_female_person-512.png',
// ></Thumbnail>
// <Text style=styles.userName>userName</Text>
// <View style=styles.addButtonContainer>
// <Button
// rounded
// style=styles.addButton
// onPress=() =>
// //addContact(Number(item.id));
// setIsSubmitted(false);
// setUserData(null);
// >
// <Icon
// name="plus"
// size=moderateScale(20)
// color="black"
// />
// </Button>
// </View>
// </View>
// );
// ,
// )
// </View>
// );
//
// ,
// [createUserRelationMutation, userData],
// );
// const addContact = React.useCallback(
// (id: Number) =>
// console.log('Whats the Id', id);
// createUserRelationMutation(
// variables:
// input: relatedUserId: id, type: RelationType.Contact, userId: 30 ,
// ,
// );
// ,
// [createUserRelationMutation],
// );
const getContactId = React.useCallback(
(data: UsersLazyQueryHookResult) =>
//resetForm();
if (data)
if (data.users.nodes.length == 0)
Alert.alert('No User Found');
else
setUserData(data);
,
//[addContact],
[],
);
const [loadUsers] = useUsersLazyQuery(
onCompleted: getContactId,
onError: _onLoadUserError,
);
const handleSubmitForm = React.useCallback(
(values: FormValues) =>
setIsSubmitted(true);
const plusSign = '+';
const newPhoneNumber = plusSign.concat(values.phoneNumber);
console.log('Submitted');
loadUsers(
variables:
where: phoneNumber: newPhoneNumber ,
,
);
resetForm();
,
[loadUsers],
);
// if (!addingContactLoading && isMutationCalled)
// if (addingContactError)
// Alert.alert('Unable to Add Contact');
//
//
return (
<SafeAreaView>
<View style=styles.container>
<View style=styles.searchTopContainer>
<View>
<View style=styles.searchFieldContainer>
<View style=styles.form>
<Item underline style=styles.newFieldInput >
<Icon name="mobile" color="black" size=26></Icon>
<Input
onChangeText=handleChange('phoneNumber') as (text: string) => void
onBlur=handleBlur('phoneNumber') as (event: any) => void
value=values.phoneNumber
placeholder="49152901820"
/>
</Item>
</View>
<View style=styles.buttonContainer>
<Button
block
danger
bordered
style=styles.button
// onPress=() => navigation.goBack()
//disabled=!isValid || !dirty
//disabled=isSubmitting
onPress=resetForm
>
<Text>Abbrechen</Text>
</Button>
<Button
block
success
disabled=!isValid || !dirty
onPress=handleSubmit
style=styles.button>
<Text>Speichern</Text>
</Button>
</View>
</View>
</View>
/* isSubmitted && showUsers(userData) */
<User data=userData></User>
</View>
</View>
</SafeAreaView>
);
;
type UserProps =
data: UsersLazyQueryHookResult;
//isSubmitted: boolean;
;
export const User: React.FunctionComponent<UserProps> = (
data,
//isSubmitted,
) =>
console.log('user called');
const [
createUserRelationMutation,
data: addingContactData,
loading: addingContactLoading,
error: addingContactError,
called: isMutationCalled,
,
] = useCreateUserRelationMutation(
onCompleted: () =>
Alert.alert('Contact Added');
,
);
const addContact = React.useCallback(
(id: Number) =>
console.log('Whats the Id', id);
createUserRelationMutation(
variables:
input: relatedUserId: id, type: RelationType.Contact, userId: 30 ,
,
);
,
[createUserRelationMutation],
);
if (!addingContactLoading && isMutationCalled)
if (addingContactError)
Alert.alert('Unable to Add Contact');
if (!data) return null;
return (
<View style=styles.users>
data.users.nodes.map(
(item: firstName: string; lastName: string; id: number ) =>
const userName = item.firstName.concat(' ').concat(item.lastName);
return (
<View style=styles.item key=item.id>
<Thumbnail
style=styles.thumbnail
source=
uri:
'https://cdn4.iconfinder.com/data/icons/avatars-xmas-giveaway/128/afro_woman_female_person-512.png',
></Thumbnail>
<Text style=styles.userName>userName</Text>
<View style=styles.addButtonContainer>
<Button
rounded
style=styles.addButton
onPress=() =>
addContact(Number(item.id));
//setIsSubmitted(false);
//setUserData(null);
>
<Icon name="plus" size=moderateScale(20) color="black" />
</Button>
</View>
</View>
);
,
)
</View>
);
;
当按钮为空(不脏)且无效(```!isValid)时,该按钮应该被禁用(灰色)。如果它脏且有效,则按钮变为绿色。目前,在运行第一个查询并获得结果后,如果我在输入字段中输入有效的内容,按钮会从灰色变为绿色。但是,我不能“点击”它。
【问题讨论】:
评论不用于扩展讨论;这个对话是moved to chat。 【参考方案1】:对您的代码进行一些更改,看看它是否有效:
使<Button>
类型提交。
确保在您的输入中提供name
(电话号码)。这就是 formik 跟踪表单值的方式。
<FieldInput style=styles.fieldInput
handleChange=handleChange
handleBlur=handleBlur
value=values.phoneNumber
fieldType="phoneNumber"
name="phoneNumber" //<<<<<<<--- like this
icon="phone"
placeholderText="49152901820"
/>
在<Formik>
中使用<form>
标签。有一个 onSubmit。
例如:
<Formik
initialValues= name: 'jared'
onSubmit=(values, actions) =>
setTimeout(() =>
alert(JSON.stringify(values, null, 2));
actions.setSubmitting(false);
, 1000);
>
( handleChange, handleBlur, handleSubmit, values, isValid, dirty ) => (
<form onSubmit=props.handleSubmit>
<input
type="text"
onChange=props.handleChange
onBlur=props.handleBlur
value=props.values.name
name="name"
/>
props.errors.name && <div id="feedback">props.errors.name</div>
<button type="submit">Submit</button>
</form>
)
</Formik>
不要改变values
。 Use resetForm
instead
const handleSubmitForm = React.useCallback(
(values: FormValues, formikBag: any) =>
setIsSubmitted(true);
const plusSign = '+';
const newPhoneNumber = plusSign.concat(values.phoneNumber);
console.log('Submitted');
loadUsers(
variables:
where: phoneNumber: newPhoneNumber ,
,
);
// values.phoneNumber = ''; //<------don't do this.. probably this could be issue as well
formikBag.resetForm()
,
[loadUsers],
);
删除所有React.useCallback
s。一旦您的表单正常工作,然后将其一一添加到所需的方法中
【讨论】:
我不能在这里对 Form 使用 onSubmit,因为 form 只是 react native 的一个包装器。我也不能在按钮上使用 type="submit" ,因为它会导致重载错误。关于表单重置的事情:我从 onSubmit 下的 useFormik 钩子调用函数。如何将 formikBag 与此处的值一起传递?onSubmit
中的第一个参数是 values
第二个参数是 formik bag .. jaredpalmer.com/formik/docs/api/…
take a look at here 看看表单重置是如何完成的......
我试过用你的方法。表单会重置,但我仍然无法解决主要问题。由于我正在使用钩子分解 resetForm,因此我应该也可以在没有 formikBag 的情况下使用它。但是,它不起作用。它重置了表单,但无法点击按钮的问题仍然存在
是否可以将所有代码放入codesandbox ...即使代码不起作用,也没关系...它为我们提供了更多可见性,以便我们可以看到所有代码...谢谢。【参考方案2】:
在评论的讨论 (enter link description here) 之后,看起来 React Native 在某些特定情况下会失败。更新的状态/变量未正确反映到渲染视图(重新渲染为未禁用的按钮不起作用)。
这不是 Formik 的错...使用useFormik
可以访问values
和整个组件中的助手。从处理程序调用的resetForm
工作正常。
我的建议是将showUsers
提取到单独的 [功能] 组件 f.e.
userData && <UserList data=userData />
或至少在多个层级上使用key
渲染<View />
组件(showUsers
渲染<View/>
与<View style=styles.searchTopContainer>
同级)。使用 key
有助于对管理虚拟 DOM 和更新视图做出反应。单独的组件实际上做同样的事情,但也降低了这个组件的复杂性。
【讨论】:
我已经尝试将 showUsers 移动到一个单独的组件中。对我没有任何影响:/ 另外,以前我在我的 showUsers 中使用setIsSubmitted(false);
和 setUserData(null);
。如果我使用单独的组件,我现在如何使用它?更新代码。
您可以在 handleSubmit 中 setUserData(null)
... 向按钮添加键(在“搜索表单”中)...。您可以仅将渲染列表移动到单独的组件中,保留加载逻辑
我想我找到了解决方法,但我遇到了错误处理问题。你能看看这里吗? ***.com/questions/62245474/…
我猜这仍然不是 SOLID 问题 - 一个地方有太多东西,变得难以管理,试图解决你的问题正在增加复杂性...分解您的逻辑 - 一个用于搜索,一个用于用户列表(简单的 useQuery 和创建关系突变) - 不会受到其他搜索结果及其突变的影响。以上是关于运行一次查询后按钮禁用的主要内容,如果未能解决你的问题,请参考以下文章