运行一次查询后按钮禁用

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】:

对您的代码进行一些更改,看看它是否有效:

使&lt;Button&gt;类型提交。 确保在您的输入中提供name(电话号码)。这就是 formik 跟踪表单值的方式。
<FieldInput style=styles.fieldInput
 handleChange=handleChange
 handleBlur=handleBlur
 value=values.phoneNumber
 fieldType="phoneNumber"
 name="phoneNumber" //<<<<<<<--- like this
 icon="phone"
 placeholderText="49152901820"
/>
&lt;Formik&gt; 中使用&lt;form&gt; 标签。有一个 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.useCallbacks。一旦您的表单正常工作,然后将其一一添加到所需的方法中

【讨论】:

我不能在这里对 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 渲染&lt;View /&gt; 组件(showUsers 渲染&lt;View/&gt;&lt;View style=styles.searchTopContainer&gt; 同级)。使用 key 有助于对管理虚拟 DOM 和更新视图做出反应。单独的组件实际上做同样的事情,但也降低了这个组件的复杂性。

【讨论】:

我已经尝试将 showUsers 移动到一个单独的组件中。对我没有任何影响:/ 另外,以前我在我的 showUsers 中使用 setIsSubmitted(false);setUserData(null);。如果我使用单独的组件,我现在如何使用它?更新代码。 您可以在 handleSubmit 中 setUserData(null) ... 向按钮添加键(在“搜索表单”中)...。您可以仅将渲染列表移动到单独的组件中,保留加载逻辑 我想我找到了解决方法,但我遇到了错误处理问题。你能看看这里吗? ***.com/questions/62245474/… 我猜这仍然不是 SOLID 问题 - 一个地方有太多东西,变得难以管理,试图解决你的问题正在增加复杂性...分解您的逻辑 - 一个用于搜索,一个用于用户列表(简单的 useQuery 和创建关系突变) - 不会受到其他搜索结果及其突变的影响。

以上是关于运行一次查询后按钮禁用的主要内容,如果未能解决你的问题,请参考以下文章

单击angularjs后禁用按钮

在 android Studio 中禁用运行和加载按钮

无法制作双向按钮(第一次单击使问题在第二次启用时禁用)

如果第一次从 App Manager 运行应用程序,为啥 Android 在按下 Home 按钮后不保留应用程序状态?

在 API 调用期间禁用按钮

jquery如何实现一个按钮只能点击一次,再点击就无效?