按需更新 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)
.
来触发按钮中的提取
然后有一个 useEffect
和 companyDataFetch
作为依赖项。
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>
)}
我正在尝试在 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)
.
然后有一个 useEffect
和 companyDataFetch
作为依赖项。
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>
)}