【问题标题】:Disable the next button until the form is filled using Reactjs禁用下一个按钮,直到使用 Reactjs 填写表单
【发布时间】:2021-04-18 07:45:13
【问题描述】:

在用户填写表单之前,我需要禁用下一步按钮。完整的组件附在此处。我需要禁用下一个按钮。此表单是在 react-hook-from 中使用材质 UI 构建的 useFrom()。这与 address1、city 和 zip 字段的 API 数据集成。下一个按钮是支付网关的流程。所以我需要禁用按钮,直到表单字段完成。只需要验证是否所有字段都已填写,一旦完成,下一步将显示点击。

  const AddressForm = ({ checkoutToken, test }) => {
  const [shippingCountries, setShippingCountries] = useState([]);
  const [shippingCountry, setShippingCountry] = useState('');
  const [shippingSubdivisions, setShippingSubdivisions] = useState([]);
  const [shippingSubdivision, setShippingSubdivision] = useState('');
  const [shippingOptions, setShippingOptions] = useState([]);
  const [shippingOption, setShippingOption] = useState('');
  const methods = useForm();

  const fetchShippingCountries = async (checkoutTokenId) => {
    const { countries } = await commerce.services.localeListShippingCountries(checkoutTokenId);

    setShippingCountries(countries);
    setShippingCountry(Object.keys(countries)[0]);
  };

  const fetchSubdivisions = async (countryCode) => {
    const { subdivisions } = await commerce.services.localeListSubdivisions(countryCode);

    setShippingSubdivisions(subdivisions);
    setShippingSubdivision(Object.keys(subdivisions)[0]);
  };

  const fetchShippingOptions = async (checkoutTokenId, country, stateProvince = null) => {
    const options = await commerce.checkout.getShippingOptions(checkoutTokenId, { country, region: stateProvince });

    setShippingOptions(options);
    setShippingOption(options[0].id);
  };

  useEffect(() => {
    fetchShippingCountries(checkoutToken.id);
  }, []);

  useEffect(() => {
    if (shippingCountry) fetchSubdivisions(shippingCountry);
  }, [shippingCountry]);

  useEffect(() => {
    if (shippingSubdivision) fetchShippingOptions(checkoutToken.id, shippingCountry, shippingSubdivision);
  }, [shippingSubdivision]);

  return (
    <>
      <Typography variant="h6" gutterBottom>Shipping address</Typography>
      <FormProvider {...methods}>
        <form onSubmit={methods.handleSubmit((data) => test({ ...data, shippingCountry, shippingSubdivision, shippingOption }))}>
          <Grid container spacing={3}>
            <FormInput required name="firstName" label="First name" />
            <FormInput required name="lastName" label="Last name" />
            <FormInput required name="address1" label="Address line 1" />
            <FormInput required name="email" label="Email" />
            <FormInput required name="city" label="City" />
            <FormInput required name="zip" label="Zip / Postal code" />
            <Grid item xs={12} sm={6}>
              <InputLabel>Shipping Country</InputLabel>
              <Select value={shippingCountry} fullWidth onChange={(e) => setShippingCountry(e.target.value)}>
                {Object.entries(shippingCountries).map(([code, name]) => ({ id: code, label: name })).map((item) => (
                  <MenuItem key={item.id} value={item.id}>
                    {item.label}
                  </MenuItem>
                ))}
              </Select>
            </Grid>
            <Grid item xs={12} sm={6}>
              <InputLabel>Shipping Subdivision</InputLabel>
              <Select value={shippingSubdivision} fullWidth onChange={(e) => setShippingSubdivision(e.target.value)}>
                {Object.entries(shippingSubdivisions).map(([code, name]) => ({ id: code, label: name })).map((item) => (
                  <MenuItem key={item.id} value={item.id}>
                    {item.label}
                  </MenuItem>
                ))}
              </Select>
            </Grid>
            <Grid item xs={12} sm={6}>
              <InputLabel>Shipping Options</InputLabel>
              <Select value={shippingOption} fullWidth onChange={(e) => setShippingOption(e.target.value)}>
                {shippingOptions.map((sO) => ({ id: sO.id, label: `${sO.description} - (${sO.price.formatted_with_symbol})` })).map((item) => (
                  <MenuItem key={item.id} value={item.id}>
                    {item.label}
                  </MenuItem>
                ))}
              </Select>
            </Grid>
          </Grid>
          <br />
          <div style={{ display: 'flex', justifyContent: 'space-between' }}>
            <Button component={Link} variant="contained" to="/cart" color="secondary">Back to Cart</Button>
            <Button type="submit" variant="contained" color="primary">Next</Button>
          </div>
        </form>
      </FormProvider>
    </>
  );
};
 

【问题讨论】:

  • 你在使用 react-hook-form 中的 useForm() 吗?
  • 是的。 import { useForm, FormProvider } from 'react-hook-form';
  • 这是我第一次尝试功能组件。我需要知道该怎么做。

标签: javascript reactjs material-ui


【解决方案1】:

您可以使用前面提到的有效函数

const isValid = shippingCountries && shippingCountry && shippingSubdivisions && shippingSubdivision && shippingOptions && shippingOption

<Button disabled={!isValid} />

当您使用 FormProvider 和 useForm() 时,我认为您使用的是 react-hook-form?如果是,那就更容易了,因为它有一个集成的验证器。

例如你可以这样使用它

const { register, handleSubmit, setValue } = useForm();
....

<form onSubmit={methods.handleSubmit((data) => test({ ...data, shippingCountry, shippingSubdivision, shippingOption }))}>
 <FormInput {...register("firstName, {required: true})}  />
</form

使用 setValue,您可以从外部设置表单的值(例如您的 useEffect 函数)

setValue([{ firstName: name }, { secondOption: option }]);

【讨论】:

  • ref={register({ required: true })} 我需要为所有表单字段添加相同的吗?
  • 正确,括号内可以定义验证器。您还可以定义其他验证器,例如 maxLeght、min、max 等。您可以在验证器下的文档中查看更多信息 => react-hook-form.com/get-started#Applyvalidation
【解决方案2】:

参考代码:

PS:你可以有一个函数返回true或false,然后启用...

【讨论】:

  • 非常感谢。这个很有用
  • 你能用完整的代码解释这个解决方案吗?我试过但很沮丧。那会很有帮助。
  • render() { const enableButton = this.state.shippingCountry.length &gt; 0 &amp;&amp; this.state.shippingDivision.length &gt; 0 &amp;&amp; this.state.shippingOption.length &gt; 0; 然后将按钮替换为&lt;button disabled={!enableButton}&gt;Next&lt;/button&gt;
猜你喜欢
  • 2018-04-21
  • 1970-01-01
  • 2021-10-08
  • 2020-11-12
  • 1970-01-01
  • 2023-03-23
  • 2012-12-05
  • 2018-01-22
  • 2011-12-07
相关资源
最近更新 更多