Reputation: 157
I want to update the value of firmDetail when there is a change in the value of input fields. To do so, I am fetching data from API and trying to assign the retrieved value from API to firmDetail in useState. But due to delays in retrieving data from API causing issues of null value in firmProfile. Here is my code:
const UseApiFetch = (url) => {
const[data, setData]= useState(null);
const[isPending, setPending]= useState(true);
const[error, setError]= useState(null);
useEffect( async ()=>{
await axios.get(url).then(
response =>{
if(!response.status=== "200"){
throw error('error while fetching data');
}
setData(response.data);
setPending(false);
console.log(response.data);
})
.catch((error => {
setPending(false);
setError(error.message);
})
)
}, [url]);
return{data, isPending, error}
}
const { data: firmProfile, isPending, error } = UseApiFetch(constants.FIRM_PROFILE_URI);
const[firmDetail, setFirmDetail]= useState({
firmName:"",
firmEmail:"",
firmPhone:"",
firmUrl:"",
pDate:"",
cRename:""
})
useEffect(()=>{
setFirmDetail({
...firmDetail,
firmName: firmProfile.firmSubscriptionDetail.firmName,
firmEmail: firmProfile.firmSubscriptionDetail.ltbDecisionEmail,
firmPhone: firmProfile.firmSubscriptionDetail.ltbDecisionPhone,
firmUrl: firmProfile.firmSubscriptionDetail.firmURL,
pDate: firmProfile.firmSubscriptionDetail.purchaseDate,
cRename: firmProfile.firmSubscriptionDetail.caseRename
})
}, [firmDetail])
// if(firmProfile){
// firmDetail.firmName = firmProfile.firmSubscriptionDetail.firmName;
// firmDetail.firmEmail=firmProfile.firmSubscriptionDetail.ltbDecisionEmail;
// firmDetail.firmPhone=firmProfile.firmSubscriptionDetail.ltbDecisionPhone;
// firmDetail.firmUrl=firmProfile.firmSubscriptionDetail.firmURL;
// firmDetail.pDate=firmProfile.firmSubscriptionDetail.purchaseDate;
// firmDetail.cRename=firmProfile.firmSubscriptionDetail.caseRename;
// }
function handleChange(evt) {
const value = evt.target.value;
setFirmDetail({
...firmDetail,
[evt.target.name]: value
});
}
return (
<div className="content">
{error && <div>{error}</div>}
{isPending &&
<div><Loader /></div>
}
<div className="firmDetail">
{ firmProfile &&
<div className="col-lg-6">
<CCard>
<CCardHeader>
Firm
<small> Profile</small>
</CCardHeader>
<CCardBody>
<CFormGroup>
<CLabel htmlFor="name">Firm Name:</CLabel>
<CInput id="firmName" name="firmName" defaultValue={firmProfile.firmSubscriptionDetail.firmName} onChange={(e)=>handleChange(e)}/>
</CFormGroup>
<CFormGroup>
<CLabel htmlFor="email">Contact Email:</CLabel>
<CInput id="firmEmail" name="firmEmail" type="email" defaultValue={firmProfile.firmSubscriptionDetail.ltbDecisionEmail} onChange={(e)=>handleChange(e)}/>
</CFormGroup>
<CFormGroup>
<CLabel htmlFor="phone">Contact Phone:</CLabel>
<CInput id="firmPhone" name="firmPhone" defaultValue={firmProfile.firmSubscriptionDetail.ltbDecisionPhone} onChange={(e)=>handleChange(e)}/>
</CFormGroup>
<CFormGroup>
<CLabel htmlFor="">Firm Url:</CLabel>
<CInput id="firmUrl" name="firmUrl" defaultValue={firmProfile.firmSubscriptionDetail.firmURL} onChange={(e)=>handleChange(e)}/>
</CFormGroup>
<CFormGroup>
<CLabel htmlFor="date">Purchase Date:</CLabel>
<CInput id="date" name="pDate" defaultValue={firmProfile.firmSubscriptionDetail.purchaseDate} onChange={(e)=>handleChange(e)}/>
</CFormGroup>
<CFormGroup>
<CLabel htmlFor="case">Case Rename</CLabel>
<CInput id="caseRename" name="cRename" defaultValue={firmProfile.firmSubscriptionDetail.caseRename} onChange={(e)=>handleChange(e)}/>
</CFormGroup>
<Row className="float-right">
<Button variant="success pull-right" className="float-right">Update</Button>
</Row>
</CCardBody>
</CCard>
</div>
}
</div>
Upvotes: 2
Views: 122
Reputation: 202605
firmDetail
can't be a dependency for the effect that unconditionally calls setFirmDetail
as this will create a render loop. I suspect you meant to use the firmProfile
data response from the UseApiFetch
hook.
The useEffect
hook will run on the initial render cycle, likely well before the GET request resolves. You should account for the possibly null firmProfile
value by checking if it exists before attempting to access nested properties. Only if it is truthy/defined should you actually enqueue a state update.
useEffect(()=>{
firmProfile && setFirmDetail({
firmName: firmProfile.firmSubscriptionDetail.firmName,
firmEmail: firmProfile.firmSubscriptionDetail.ltbDecisionEmail,
firmPhone: firmProfile.firmSubscriptionDetail.ltbDecisionPhone,
firmUrl: firmProfile.firmSubscriptionDetail.firmURL,
pDate: firmProfile.firmSubscriptionDetail.purchaseDate,
cRename: firmProfile.firmSubscriptionDetail.caseRename,
})
}, [firmProfile]);
Render from the firmDetail
state in your JSX
{!isPending &&
<div className="col-lg-6">
<CCard>
<CCardHeader>
Firm
<small> Profile</small>
</CCardHeader>
<CCardBody>
<CFormGroup>
<CLabel htmlFor="name">Firm Name:</CLabel>
<CInput
id="firmName"
name="firmName"
value={firmDetail.firmName} // <-- controlled input
onChange={handleChange}
/>
</CFormGroup>
...
Upvotes: 1