首页 > 解决方案 > React Hook "useEffect" 被有条件地调用,在所谓的简单的 get-display-retrieve 输入组件中

问题描述

请帮忙,我在绕圈子(React 新手)。
我要么得到“有条件地调用 React Hook “useState”,如果我将其更改为下面的代码,
我得到“有条件地调用 React Hook “useEffect”。

这个想法是

  1. 通过 useQuery 检索数据,并通过 props 输入数据库记录 ID。
  2. 如果该数据为空,例如查询使用 id=0(如插入而不是更新记录),则 deviceObject 为空记录,否则为检索到的数据。
  3. 将“deviceObject”设置为状态。

ie 顺序很重要,但是 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();

标签: reactjsreact-hooksreact-functional-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 (...);
}


推荐阅读