React Hooks 渲染的钩子比上一次渲染时更多

时间:2021-03-01 16:09:04

标签: javascript reactjs react-hooks

呈现已填写表单的预览的组件,当您单击左侧的表单时,它会在右侧显示它们。

第一个 handleSwitchReview 向我抛出 React Hooks Rendered 比上一个渲染错误期间更多的钩子

第二个没有。例如,当我控制台记录道具时,当显示第一个函数的视图时,我得到它们 4-5 次,但不是第二个,第二个仅在控制台日志中显示 1 次。

尝试移动 setState 并在控制台中记录父组件,但该组件是唯一一个多次触发并损坏的组件,也许我只是对如何构建它没有明确的理解。

const SimpleFormPreview = (props) => {
    //Deconstructing Props
    const { childAndButtonWithStylesForPreview } = props;

    //Setting State
    const [child, setChild] = useState({
        childToDisplay: childAndButtonWithStylesForPreview ? childAndButtonWithStylesForPreview[0].child : {}
    });

    //Deconstructing State
    const { childToDisplay } = child;

    const handleSwitchReview = (childWithIconArr) => {
        setChild({ childToDisplay: childWithIconArr.child });
    };

    const renderPreview = () => {
        if (childToDisplay.hasOwnProperty('schema')) {
            return <SimpleFormView children={undefined} schema={childToDisplay.schema} onValChange={{}} onSatisfiedOrPercentageChange={{}} vals={{}} existingLookupOriginalVals={{}} nonStandardKeysInPropInfo={{}} satisfiedOverrides={{}} />;
        } else {
            var reviewItems = _.map(childToDisplay, function (val, key) {
                console.log('here', val, key);
                if (!key.startsWith('customer') && (key.startsWith('custom') || key.endsWith('Cost'))) {
                    //skip rendering these
                    //they will be attached to the main settings rendering below
                    return null;
                } else {
                    if (key === '_id' || key === 'id') {
                        return null;
                    }

                    var costEl;
                    var customEl;

                    _.each(childToDisplay, function (customOrCostVal, customOrCostKey) {
                        if (customOrCostKey === 'custom' + key) {
                            customEl = (
                                <div
                                    style={{
                                        display: 'inline-block',
                                        marginLeft: 5,
                                        color: 'rgb(222, 222, 0)'
                                    }}>
                                    {'Customized to ' + customOrCostVal.toString()}
                                </div>
                            );
                        }

                        if (customOrCostKey === key + 'Cost') {
                            costEl = (
                                <div
                                    style={{
                                        display: 'inline-block',
                                        color: 'rgba(39, 204, 39, 0.52)',
                                        marginRight: 20
                                    }}>
                                    {'+ $' + customOrCostVal.val}
                                </div>
                            );

                            totalAdditionalCost = totalAdditionalCost + customOrCostVal.val;
                        }
                    });
                    return (
                        <div key={key}>
                            {costEl}
                            <div style={{ display: 'inline-block', marginLeft: 5 }}>{key.toString()}</div>:<div style={{ display: 'inline-block', marginLeft: 5 }}>{val.toString()}</div>
                            {customEl}
                        </div>
                    );
                }
            });
            return reviewItems;
        }
    };

    return (
        <Grid container direction='column' justify='flex-start' spacing={0}>
            <Grid item xs={12}>
                <Grid container wrap='wrap' spacing={0}>
                    <Grid style={{ position: 'fixed', width: 100 }} container direction='column'>
                        <div style={{ marginLeft: 'auto', height: 447, overflowY: 'scroll', direction: 'rtl', background: 'transparent' }}>
                            {_.map(childAndButtonWithStylesForPreview, function (childObj, idx) {
                                var innerIconElText = '';
                                // if ((idx + 1) > 99) {
                                //     innerIconElText = '...' + (idx + 1)
                                // } else {
                                //     innerIconElText = idx + 1
                                // }
                                if (childObj.iconEl) {
                                    childObj.iconEl.props.style.boxShadow = childToDisplay.id === childObj.child.id ? 'green 0px 0px 33px 5px' : null;
                                    return <div onClick={() => handleSwitchReview(childObj)} key={idx}>{childObj.iconEl}</div>;
                                } else {
                                    return (
                                        <Button style={{ boxShadow: childToDisplay.id === childObj.child.id ? 'green 0px 0px 33px 5px' : null, height: 100, margin: '25px', borderRadius: 60 }} key={idx} onClick={() => handleSwitchReview(childObj)}>
                                            <span id='defaultChildIcon' style={{ position: 'relative' }}></span>
                                            <span style={{ marginLeft: 22, marginTop: 10, fontSize: 12, position: 'absolute' }}>{innerIconElText}</span>
                                        </Button>
                                    );
                                }
                            })}
                        </div>
                    </Grid>
                    <Grid id={'simpleForm'} style={{ height: '100%', width: '100%', overflow: 'auto' }} container>
                        <Paper style={{ marginTop: '25px', marginLeft: '165px', padding: '15px', width: '80%' }} elevation={24}>
                            hello
                            <div style={{ float: 'right' }}>
                                <Button id='localSaveBtn' onClick={() => handleSave(document.querySelector('#simpleForm'))} variant='contained' color='secondary' size='large' style={{}}>
                                    Save File
                                </Button>
                            </div>
                        </Paper>
                    </Grid>
                </Grid>
            </Grid>
        </Grid>
    );
};

export default SimpleFormPreview;

1 个答案:

答案 0 :(得分:1)

在 if 语句“ if (childObj.iconEl) ”之后直接改变 prop 会导致应用重复渲染。

使用 cloneElement 我能够让我的元素将原始元素的道具与新道具浅合并:reactjs.org/docs/react-api.html#cloneelement 错误停止了,我能够实现所需的结果是更改作为道具传递给子元素的按钮的 onClick 框阴影。

下面是替换“ if (childObj.iconEl) ” If Condition之后的代码。

                                    var clonedElementWithInjectedStyles = React.cloneElement(childObj.iconEl, { style: { ...childObj.iconEl.props.style, boxShadow: childToDisplay.id === childObj.child.id ? 'green 0px 0px 33px 5px' : null } });
                                    return (
                                        <div onClick={() => handleSwitchReview(childObj)} key={idx}>
                                            {clonedElementWithInjectedStyles}
                                        </div>
                                    );