React Hook "useEffect" 被有条件地调用,在假定简单的 get-display-retrieve 输入组件中
React Hook "useEffect" is called conditionally, in supposedly simple get-display-retrieve inputs component
请帮忙,
我在兜圈子(React 新手)。
我要么得到 'React Hook "useState" is called conditionally',如果我将其更改为下面的代码,
我得到 'React Hook "useEffect" is called conditionally'.
想法是
- 通过 useQuery 检索数据并通过 props 传入数据库记录 ID。
- 如果该数据为空,例如查询使用 id=0(就像插入而不是更新记录),然后 deviceObject 到空记录,否则到检索到的数据。
- 将 'deviceObject' 设置为状态。
即顺序很重要,但是 setRow 应该只被调用一次,而不是多次,这会导致渲染过多导致反应崩溃。
export default function DeviceModal(props) {
const dataRowId = props.dataRowId;
const classes = useStyles();
const [row, setRow] = useState('')
const device = useQuery(getDevice_query, {variables: {id: dataRowId}});
if (device.loading) return <DataLoader/>;
if (device.error) return <p style={{color: 'white'}}>{("GraphQL Error " + device.error)})</p>;
// Create an empty recordObject to be populated and sent back for insert to db.
const emptyDevice = {
id : 0,
deviceId : 0,
deviceClass :{name : '',},
serialNumber: 0,
}
const deviceObject = device.data.getDevice !== null ? device.data.getDevice : emptyDevice;
useEffect(()=>{
setRow(deviceObject)
},[])
const handleSave = (value) => {
};
const HandleChange = e => {
useEffect(()=>{
setRow({...row, [e.target.name]: e.target.value })
},[])
};
return (
<div>
<Modal ...>
<div className={classes.paper}>
<Grid container direction="row" justify="center" alignItems="center">
<Grid item xs={4}>
<TextField
id="deviceId"
name="deviceId"
defaultValue={row.deviceId}
onChange={HandleChange}
/>
</Grid>
</Grid>
{/* 30 other textfields to capture*/}
....
</div>
</Modal>
</div>
)};
Edit as per Long Nguyen:
// Set the device object record to be either the empty record, or the records retrieved from db if those are populated (not null)
let deviceObject = {};
const Component = () => {
deviceObject = device.data.getDevice !== null ? device.data.getDevice: emptyDevice;
return <RefactorComponent />;
}
// Set the device object (empty or populated with db-retrieved rows,) into state
const RefactorComponent = () =>
{
useEffect(()=>{
setRow(deviceObject)
},[deviceObject])
// return ()
}
Component();
你在条件之后调用了钩子。它使您调用的钩子在渲染之间不会以相同的顺序出现,因为“React 依赖于调用钩子的顺序”。
您可以在本文档中找到有用的信息,以及解决问题的方法。
https://reactjs.org/docs/hooks-rules.html#explanation
更新:
- 当然,你不应该把挂钩放在把手上。
- 如果您仍想保留原始代码,可以像这样将条件后的块提取到其他组件
const Component = () => {
if(conditions) return <Other />
// bad, this hook order is not fixed
// it can appear or not
useEffect(() => {
...the effect after condition...
});
return (...);
}
const Component = () => {
if(conditions) return <Other />
return <RefactorComponent />
}
const RefactorComponent = () => {
// ✅ ok, the hooks order is fixed
useEffect(() => {
...the effect after condition...
});
return (...);
}
请帮忙,
我在兜圈子(React 新手)。
我要么得到 'React Hook "useState" is called conditionally',如果我将其更改为下面的代码,
我得到 'React Hook "useEffect" is called conditionally'.
想法是
- 通过 useQuery 检索数据并通过 props 传入数据库记录 ID。
- 如果该数据为空,例如查询使用 id=0(就像插入而不是更新记录),然后 deviceObject 到空记录,否则到检索到的数据。
- 将 'deviceObject' 设置为状态。
即顺序很重要,但是 setRow 应该只被调用一次,而不是多次,这会导致渲染过多导致反应崩溃。
export default function DeviceModal(props) {
const dataRowId = props.dataRowId;
const classes = useStyles();
const [row, setRow] = useState('')
const device = useQuery(getDevice_query, {variables: {id: dataRowId}});
if (device.loading) return <DataLoader/>;
if (device.error) return <p style={{color: 'white'}}>{("GraphQL Error " + device.error)})</p>;
// Create an empty recordObject to be populated and sent back for insert to db.
const emptyDevice = {
id : 0,
deviceId : 0,
deviceClass :{name : '',},
serialNumber: 0,
}
const deviceObject = device.data.getDevice !== null ? device.data.getDevice : emptyDevice;
useEffect(()=>{
setRow(deviceObject)
},[])
const handleSave = (value) => {
};
const HandleChange = e => {
useEffect(()=>{
setRow({...row, [e.target.name]: e.target.value })
},[])
};
return (
<div>
<Modal ...>
<div className={classes.paper}>
<Grid container direction="row" justify="center" alignItems="center">
<Grid item xs={4}>
<TextField
id="deviceId"
name="deviceId"
defaultValue={row.deviceId}
onChange={HandleChange}
/>
</Grid>
</Grid>
{/* 30 other textfields to capture*/}
....
</div>
</Modal>
</div>
)};
Edit as per Long Nguyen:
// Set the device object record to be either the empty record, or the records retrieved from db if those are populated (not null)
let deviceObject = {};
const Component = () => {
deviceObject = device.data.getDevice !== null ? device.data.getDevice: emptyDevice;
return <RefactorComponent />;
}
// Set the device object (empty or populated with db-retrieved rows,) into state
const RefactorComponent = () =>
{
useEffect(()=>{
setRow(deviceObject)
},[deviceObject])
// return ()
}
Component();
你在条件之后调用了钩子。它使您调用的钩子在渲染之间不会以相同的顺序出现,因为“React 依赖于调用钩子的顺序”。
您可以在本文档中找到有用的信息,以及解决问题的方法。
https://reactjs.org/docs/hooks-rules.html#explanation
更新:
- 当然,你不应该把挂钩放在把手上。
- 如果您仍想保留原始代码,可以像这样将条件后的块提取到其他组件
const Component = () => {
if(conditions) return <Other />
// bad, this hook order is not fixed
// it can appear or not
useEffect(() => {
...the effect after condition...
});
return (...);
}
const Component = () => {
if(conditions) return <Other />
return <RefactorComponent />
}
const RefactorComponent = () => {
// ✅ ok, the hooks order is fixed
useEffect(() => {
...the effect after condition...
});
return (...);
}