【问题标题】:How to prevent reRender of React const which uses useState如何防止使用 useState 的 React const 的 reRender
【发布时间】:2021-10-15 19:15:27
【问题描述】:

我试图阻止在 React 功能组件中重新渲染,但不确定如何或实现什么来实现这一点。 阅读建议使用备忘录,但我不明白如何在这里实现它。

props 包括 'selectAll' (propType=boolean ),onSelected 是一个回调函数,我使用 stateHook 进行选择。

因此,如果调用 'setSelected(newSelects)' 方法,它会进入无限的 reRender 循环; 我有一个关于返回标记的工作,它有效,但我更愿意使用、学习和理解管理 React 的状态。

代码:

function OptimiserTableBody(props) {
    const {Id, columns, send, onSelected, selectAll} = props;
    const [selected, setSelected] = useState([]);

    // Retrieve the data 
    const resOData = useQuery(o_data_query, {
    variables: {
        id: id,
        use: use
    },
    fetchPolicy: 'cache-and-network'
});

// Create an array from the retrieved data for the table, this is used to create the table rows
let steps = resOData.data != undefined ?  resOData.data.jobO.data : [];

 useEffect(() => {
    if (selectAll === true) {
        let newSelects = steps.map((n) => n.workStepId);
        setSelected(newSelects);
    }
}, [selectAll])


 return (
     <TableBody>
         {steps.map((step, index) => (
             let isItemSelected = isSelected(step.workStepId);
             
             // Workaround
             if (selectAll === true)
             {
                 isItemSelected = true;
             }
             return (
                 <TableRow ... >

                    <TableCell  key={'select'}  padding="checkbox"  >
                        <Checkbox 
                            checked={isItemSelected}
                             inputProps={{ 'aria-labelledby': step.workStepId }}
                                            style={{color: kbaColors.grey1}}
                                            onClick={(event) => handleClick(event, step.workStepId)}
                        />
                    </TableCell>
               </TableRow>
         ))}
      </TableBody>
    );
}
export default React.memo(OptimiserTableBody);

谢谢

【问题讨论】:

    标签: reactjs react-hooks state rendering rerender


    【解决方案1】:

    由于您在每次渲染时都setSelected,因此组件会按照您所说的重新渲染,并进入无限循环。我相信您想根据selectAll 更新selected。您可以在 useEffect 中执行此操作:

    import {useEffect} from 'react'
    
    useEffect(() => {
      if(selectAll){
        let newSelects = steps.map((n) => n.workStepId);
        setSelected(newSelects);
      }
    }, [selectAll, steps])
    
    

    通过将selectAll 赋予依赖数组,您可以确保此useEffect 仅在selectAll 更改时运行。

    更新

    我注意到您需要使用steps 作为状态变量。所以你可以有两个单独的useEffects:

     const [selected, setSelected] = useState([]);
     const [steps, setSteps] = useState([]);
     useEffect(() => {
        const resOData = useQuery(o_data_query, {
        variables: {
            id: id,
            use: use
        },
        fetchPolicy: 'cache-and-network'
        setSteps(resOData.data != undefined ? resOData.data.jobO.data : [])
     }, [] )   
    
    

    空依赖数组确保useEffect 在组件挂载时只运行一次。在另一个之前添加这个useEffect,你应该很高兴

    【讨论】:

    • 听起来不错,但是当我尝试它时,我得到一个编译错误,... React Hook "useEffect" 被有条件地调用。在每个组件渲染中,必须以完全相同的顺序调用 React Hooks。您是否在提前返回后不小心调用了 React Hook?
    • 可能是排序错误。返回应该在最底部。
    • 好的,我编辑了问题,返回在最后。我也在尝试创建第二个 useEffect,但它不喜欢 setSteps(resOData.data 中的语法“.data”
    • 我添加了最后一个大括号和导出默认行。我想我解决了我遇到的语法错误。
    • 好了,整理出React Hook "useEffect" 是有条件调用的。它有效。谢谢!!
    猜你喜欢
    • 2020-03-17
    • 2016-08-17
    • 2021-12-10
    • 1970-01-01
    • 2020-03-10
    • 1970-01-01
    • 2021-12-04
    • 1970-01-01
    相关资源
    最近更新 更多