按需更新 React 输入字段值

Update React input fields values on demand

我正在尝试在 React 中实现一个两页表单。在第一页上,我请求一个代码,用于获取一些我需要在第二页上显示的数据。在这里,按页面我指的是同一页面上的不同视图。我面临的问题是,当我收到来自后端 API 的响应时,我使用 state 来更新字段的当前状态,这似乎不会在我需要时立即发生。当我更改决定呈现哪个视图的 属性 的值时,字段仍然是空的,没有更新从 API 中获取的值。现在,我知道 setState 是异步的,但我不知道如何处理这种情况,因为数据获取是按需完成的,而不是在开始时,所以我认为我不能将 useEffect 用于这项工作。

这是我的状态:

  const [state, setState] = useState({
    name: "",
    cif: "",
    address: "",
    phone: "",
    fax: "",
    managerName: "",
    email: "",
    password: "",
  });
  const [companyDataFetched, setCompanyDataFetched] = useState(false);

下面是两个视图以及我如何在它们之间切换:

{!companyDataFetched ? (
              <CustomForm layout={theme.layout} widthelem={"70%"}>
                <Form.Item
                  name="Company CIF:"
                  label="Company CIF:"
                  rules={[
                    {
                      pattern: new RegExp(/^\d{2,10}$/),
                      message: "Invalid CIF!",
                    },
                    {
                      required: true,
                      message: "Please insert the CIF of the company!",
                    },
                  ]}
                >
                  <CustomInput
                    backgroundcolor={theme.white}
                    onChange={(event) => handleChange(event, "cif")}
                  />
                </Form.Item>
                <CustomButton
                  backgroundcolor={theme.primaryColor}
                  textcolor={theme.white}
                  onClick={() => {
                    axios.get(`${process.env.REACT_APP_API_URL}/Company/GetByCUI/${state.cif}`)
                      .then((res) => {
                        const companyInfo = res.data;

                        if (companyInfo.name) {
                          setState((prevState) => {
                            return {
                              ...prevState,
                              name: companyInfo.name
                            };
                          });
                        }

                        if (companyInfo.address) {
                          setState((prevState) => {
                            return {
                              ...prevState,
                              "address": companyInfo.address,
                            };
                          });
                        }

                        if (companyInfo.phone) {
                          setState((prevState) => {
                            return {
                              ...prevState,
                              "phone": companyInfo.phone,
                            };
                          });
                        }

                        if (companyInfo.fax) {
                          setState((prevState) => {
                            return {
                              ...prevState,
                              "fax": companyInfo.fax,
                            };
                          });
                        }

                        setCompanyDataFetched(true);
                      })
                      .catch((error) => {
                        console.log(error);
                      });
                  }}
                  margintop={"13%"}
                  marginbottom={"13%"}
                >
                  Continue
                </CustomButton>
              </CustomForm>
            ) : (
              <CustomForm layout={theme.layout} widthelem={"70%"}>
                <Form.Item
                  name="Company name:"
                  label="Company name:"
                  rules={[
                    {
                      required: true,
                      message: "Please insert the name of the company!",
                      whitespace: true,
                    },
                  ]}
                >
                  <CustomInput
                    backgroundcolor={theme.white}
                    onChange={(event) => handleChange(event, "name")}
                    value={state.name}
                  />
                </Form.Item>
                <Form.Item
                  name="Company CIF:"
                  label="Company CIF:"
                  rules={[
                    {
                      pattern: new RegExp(/^\d{2,10}$/),
                      message: "Invalid CIF!",
                    },
                    {
                      required: true,
                      message: "Please insert the CIF of the company!",
                    },
                  ]}
                >
                  <CustomInput
                    backgroundcolor={theme.white}
                    onChange={(event) => handleChange(event, "cif")}
                    value={state.cif}
                    disabled={true}
                  />
                </Form.Item>
                <Form.Item
                  name="Address:"
                  label="Address:"
                  rules={[
                    {
                      required: true,
                      message: "Please insert the address of the company!",
                      whitespace: true,
                    },
                  ]}
                >
                  <CustomInput
                    backgroundcolor={theme.white}
                    onChange={(event) => handleChange(event, "address")}
                    value={state.address}
                  />
                </Form.Item>
                <Form.Item
                  name="Phone:"
                  label="Phone:"
                  rules={[
                    {
                      required: true,
                      message:
                        "Please insert the phone number of the company!",
                      whitespace: true,
                    },
                  ]}
                >
                  <CustomInput
                    backgroundcolor={theme.white}
                    onChange={(event) => handleChange(event, "phone")}
                    value={state.phone}
                  />
                </Form.Item>
                <Form.Item
                  name="Fax:"
                  label="Fax:"
                  rules={[
                    {
                      required: true,
                      message: "Please insert the fax of the company!",
                      whitespace: true,
                    },
                  ]}
                >
                  <CustomInput
                    backgroundcolor={theme.white}
                    onChange={(event) => handleChange(event, "fax")}
                    value={state.fax}
                  />
                </Form.Item>
                <Form.Item
                  name="Manager name:"
                  label="Manager name:"
                  rules={[
                    {
                      required: true,
                      message:
                        "Please, insert the name of the company manager!",
                      whitespace: true,
                    },
                  ]}
                >
                  <CustomInput
                    backgroundcolor={theme.white}
                    onChange={(event) =>
                      handleChange(event, "managerName")
                    }
                  />
                </Form.Item>
                <Form.Item
                  name="Manager e-mail:"
                  label="Manager e-mail:"
                  rules={[
                    {
                      type: "email",
                      message: "Invalid e-mail!",
                    },
                    {
                      required: true,
                      message:
                        "Please insert the e-mail of the company manager!",
                    },
                  ]}
                >
                  <CustomInput
                    backgroundcolor={theme.white}
                    onChange={(event) => handleChange(event, "email")}
                  />
                </Form.Item>
                <Form.Item
                  name="Password:"
                  label="Password:"
                  rules={[
                    {
                      required: true,
                      message: "Please, insert a password!",
                    },
                    {
                      min: 4,
                      message: "Password needs to be at least 4 characters long",
                    },
                  ]}
                >
                  <CustomInput
                    backgroundcolor={theme.white}
                    onChange={(event) => handleChange(event, "password")}
                    type={"password"}
                    onKeyPress={verifyCredentials}
                  />
                </Form.Item>
                <CustomButton
                  backgroundcolor={theme.primaryColor}
                  textcolor={theme.white}
                  onClick={() => {
                    signup();
                  }}
                  margintop={"13%"}
                  marginbottom={"13%"}
                >
                  Register
                </CustomButton>
              </CustomForm>
            )}

主要问题是,当 companyDataFetched 变为 true 时,包含字段值的状态不会更新,并且字段的值不会随着从后端获取的数据而更新。我该如何处理这个问题?

[根据派曼的建议更新]

我尝试使用 useEffect 和另一个状态作为 API 响应,但结果是一样的。

这是我更新后的代码:

  useEffect(() => {
    if (companyDataFetched) {
      console.log(response);

      setState((prevState) => {
        return {
          ...prevState,
          nume: response.name,
          adresa: response.address,
          telefon: response.phone,
          fax: response.fax
        }
      });
    }
  }, [companyDataFetched, response]);
axios.get(`${process.env.REACT_APP_INTERNSHIP_API_URL}/Company/GetByCUI/${state.cif}`)
     .then((res) => {
       setResponse(res.data);
       setCompanyDataFetched(true);
     })
     .catch((error) => {
       console.log(error);
     });

[根据 SANGEET 的建议更新]

我尝试使用您建议的方法。它没有直接工作,所以我做了一些更改,但它还没有工作。

这是我更新后的代码:

useEffect(() => {
    const fetchData = () => {
        return axios
           .get(`${process.env.REACT_APP_INTERNSHIP_API_URL}/Company/GetByCUI/${state.cif}`)
           .then((res) => {
               return res;
           })
           .catch((error) => {
               console.log(error);
           });
    };

    let isMounted = true;
 
    if (companyDataFetched) {
        (async () => {
            const response = await fetchData();

            if (isMounted) {
                setState((prevState) => {
                    return {
                        ...prevState,
                        name: response.data.name,
                        address: response.data.address,
                        phone: response.data.phone,
                        fax: response.data.fax,
                    };
                });
            } else {
                setCompanyDataFetched(false);
            }
        })();
    }
  
    return function () {
        isMounted = false;
    };
}, [companyDataFetched, state.cif]);

[更新!] 多步表单实现。假设您在第 1 步中获得了 phone 号码,然后在第 2 步中通过电子邮件发送。

// component.js
export default function MultiForm(){
 const [step , setStep] = useState(1);
 const [inputs , setInputs] = useState({
    phone : '',
    email : ''
 });
const handleStep1 = () => {
// validation
 if(inputs.phone !== ""){
    // set step 2
     setStep(2)
  }
}
}
     const handleStep2 = async() => {
// validation
 if(inputs.email !== ""){
    const { data , status } = await axios.post(url ,{
       phone : inputs.phone,
       email : inputs.email
     })
     if(status === 200){
         alert('Registered successfully')
      }
  }
}
}
 return (
    <>
     {step === 1 && (
            <>
        <input name="phone" onChange={(e) =>{
            setInputs({...inputs , [e.target.name] : e.target.value})
        }} />
      <button onClick={handleStep1}>Continue</button>
      </>
    )}
   {step === 2 && (
             <input name="email" onChange={(e) =>{
            setInputs({...inputs , [e.target.name] : e.target.value})
        }} />
      <button onClick={handleStep2}>Submit</button>

   )}

    </>
 )
  }

没有在 onClick 处理程序中调用 API。而是通过说 setCompanyDataFetch(true).

来触发按钮中的提取

然后有一个 useEffectcompanyDataFetch 作为依赖项。

function fetchData() {  
   return axios.get(`${process.env.REACT_APP_INTERNSHIP_API_URL}/Company/GetByCUI/${state.cif}`)
         .then((res) => {
           // setResponse(res.data);
           // setCompanyDataFetched(true);
           return res;
         })
         .catch((error) => {
           console.log(error);
         });
}

你的useEffect看起来像这样

  useEffect(() => {
    let isMounted = true;
    if (companyDataFetched) {
      (async () => {
       const response = await fetchData() 
       if (isMounted) setState((prevState) => {
                        return {
                          ...prevState,
                          nume: response.name,
                          adresa: response.address,
                          telefon: response.phone,
                          fax: response.fax
                        }
                      });   
      if (isMounted) setCompanyDataFetched(false);      
     })();
    }
    return function () {
      isMounted = false;
    };
  }, [companyDataFetched]); 

经过大量研究,我发现我以错误的方式设置了输入字段值。显然,在使用 antd Form 时,必须对其进行初始化并使用其引用来动态更改 Form.Item 值,如下所示:

const [form] = Form.useForm();
const [step, setStep] = useState(1);
const [state, setState] = useState({
  name: "",
  cif: "",
  address: "",
  phone: "",
  fax: "",
  contactName: "",
  email: "",
  password: "",
});

const fetchCompanyData = async () => {
  const response = await axios.get(`${process.env.REACT_APP_INTERNSHIP_API_URL}/Company/GetByCUI/${state.cif}`);

    setState((prevState) => {
      return {
        ...prevState,
        nume: response.data.denumire,
        adresa: response.data.adresa,
        telefon: response.data.telefon,
        fax: response.data.fax,
      };
    });

    form.setFieldsValue({
      nume: response.data.denumire,
      cif: state.cif,
      adresa: response.data.adresa,
      telefon: response.data.telefon,
      fax: response.data.fax,
    });

    setStep(2);
  };
};

[...]

{step === 1 && (
<CustomForm form={form} layout={theme.layout} widthelem={"70%"}>
  <Form.Item
    name="Company name:"
    label="Company name:"
    rules={[
      {
        pattern: new RegExp(/^\d{2,10}$/),
        message: "Invalid CIF!",
      },
      {
        required: true,
        message: "Please insert the company CIF!",
      },
    ]}
  >
    <CustomInput
      backgroundcolor={theme.white}
      onChange={(event) => handleChange(event, "cif")}
    />
  </Form.Item>
  <CustomButton
    backgroundcolor={theme.primaryColor}
    textcolor={theme.white}
    onClick={fetchCompanyData}
    margintop={"13%"}
    marginbottom={"13%"}
  >
    Continue
  </CustomButton>
<CustomForm>
)}
{step === 2 && (
<CustomForm form={form} layout={theme.layout} widthelem={"70%"}>
  <Form.Item
    name="Company name:"
    label="Company name:"
    rules={[
      {
        required: true,
        message: "Please insert the name of the company!",
        whitespace: true,
      },
    ]}
  >
    <CustomInput
      backgroundcolor={theme.white}
      onChange={(event) => handleChange(event, "name")}
    />
  </Form.Item>
  [...]
<CustomForm>
)}