Reactjs 无法分配从useState内部的api检索到的值

Reactjs 无法分配从useState内部的api检索到的值,reactjs,api,react-hooks,use-effect,use-state,Reactjs,Api,React Hooks,Use Effect,Use State,当输入字段的值发生更改时,我想更新firmDetail的值。为此,我从API获取数据,并尝试将从API检索到的值分配给useState中的firmDetail。但由于从API检索数据的延迟,导致firmProfile中出现空值问题。这是我的密码: const UseApiFetch = (url) => { const[data, setData]= useState(null); const[isPending, setPending]= useState(true);

当输入字段的值发生更改时,我想更新firmDetail的值。为此,我从API获取数据,并尝试将从API检索到的值分配给useState中的firmDetail。但由于从API检索数据的延迟,导致firmProfile中出现空值问题。这是我的密码:

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>
const UseApiFetch=(url)=>{
const[data,setData]=useState(null);
const[isPending,setPending]=useState(true);
const[error,setError]=useState(null);
useffect(异步()=>{
等待axios.get(url),然后(
响应=>{
如果(!response.status==“200”){
抛出错误(“获取数据时出错”);
}
setData(response.data);
setPending(假);
console.log(response.data);
})
.catch((错误=>{
setPending(假);
setError(error.message);
})
)
},[url]);
返回{data,isPending,error}
}
const{data:firmProfile,isPending,error}=UseApiFetch(constants.FIRM_PROFILE_URI);
const[firmDetail,setFirmDetail]=useState({
公司名称:“,
电邮:「,
固定电话:“,
firmUrl:“”,
更新日期:“,
名字:“
})
useffect(()=>{
固定细节({
…非常详细,
firmName:firmProfile.firmSubscriptionDetail.firmName,
firmEmail:firmProfile.firmSubscriptionDetail.ltbDecisionEmail,
firmPhone:firmProfile.firmSubscriptionDetail.ltbDecisionPhone,
firmUrl:firmProfile.firmSubscriptionDetail.firmUrl,
更新日期: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;
// }
功能手柄更改(evt){
常量值=evt.target.value;
固定细节({
…非常详细,
[evt.target.name]:值
});
}
返回(
{error&&{error}
{iSping&&
}
{firmProfile&&
坚定的
轮廓
公司名称:
handleChange(e)}/>
联络电邮:
handleChange(e)}/>
联络电话:
handleChange(e)}/>
固定网址:
handleChange(e)}/>
购买日期:
handleChange(e)}/>
案例重命名
handleChange(e)}/>
更新
}

firmDetail
不能是无条件调用
setFirmDetail
的效果的依赖项,因为这将创建一个渲染循环。我怀疑您是想使用
UseApiFetch
钩子中的
firmProfile
数据响应

useffect
钩子将在初始渲染周期运行,很可能在GET请求解析之前运行。在尝试访问嵌套属性之前,您应该通过检查可能为null的
firmProfile
值是否存在来说明该值。只有当该值为truthy/defined时,您才应该实际将状态更新排入队列

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]);
从JSX中的
firmDetail
状态进行渲染

{!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>
        ...
{!我正在发短信&&
坚定的
轮廓
公司名称:

谢谢,它起作用了。但是你能告诉我为什么我更喜欢firmDetail而不是firmProfile。这两种用法不都一样吗?@Sujan这主要是基于上下文的预感。你没有在任何地方使用
firmDetail
状态,但你是根据最初从
firmProfile
收到的值来更新它的。尽管现在我在看y我们的代码您似乎通过使用
defaultValue
属性和
onChange
处理程序混合了部分受控和非受控输入。如果您想要完全受控的输入,那么您应该使用
value
属性,如果您想要完全非受控的输入,那么您应该使用
defaultValue
并等待渲染r输入,直到填充了
firmProfile
。感谢您的支持help@Sujan非常欢迎!如果此答案有助于解决您的问题,那么我邀请您将其标记为已接受。干杯,祝您好运。