运行一次查询后,按钮将被禁用

问题描述 投票:0回答:1

我有一个用户输入电话号码的屏幕。我运行一个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>
  );
};

编辑:

正如评论中所建议的那样 我试着用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)时,按钮应该被禁用(灰色)。如果是脏和有效,按钮就会变成绿色。目前,在运行第一个查询并得到结果后,如果我在输入字段中输入有效的东西,按钮确实从灰色变成了绿色。但是,我不能 "点击 "它。

javascript reactjs react-native graphql formik
1个回答
2
投票

对你的代码做一些修改,看看是否能用。

  • make <Button> 键入提交。
  • 请确保提供一个 name (phoneNumber)到你的输入。这就是formik跟踪表单值的方式。
<FieldInput style={styles.fieldInput}
 handleChange={handleChange}
 handleBlur={handleBlur}
 value={values.phoneNumber}
 fieldType="phoneNumber"
 name="phoneNumber" //<<<<<<<--- like this
 icon="phone"
 placeholderText="49152901820"
/>
  • 使用 <form> 内标签 <Formik>. 有一个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>
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.useCallbacks. 一旦你的表格工作了,那么就把它添加到所需的方法中去。

0
投票

在评论的讨论之后(请在此输入链接描述)看起来React Native在某些特定场景下失败了。更新后的statevariables不能正确地反映到渲染视图中(按钮重新渲染为未禁用不能工作)。

这不是Formik的错......使用的是 useFormik 提供了访问的可能性 values 和 helpers。resetForm 从handlers中调用的函数可以正常工作。

我的建议是提取 showUsers 变成单独的[功能]组件,例如:

 {userData && <UserList data={userData} />}

或至少使用 key 在渲染 <View /> 级别的组件,如果有一个以上的(showUsers 呈现的 <View/> 趋之若鹜 <View style={styles.searchTopContainer}> ). 使用 key 帮助反应管理虚拟DOM和更新视图。单独的组件其实也是这样做的,但也降低了这个组件的复杂性。

© www.soinside.com 2019 - 2024. All rights reserved.