Jacob
Jacob

Reputation: 105

React Hooks Rendered more hooks than during the previous render

A component that renders a preview of filled out forms, as you click on the forms on the left it displays them on the right.

The first handleSwitchReview throws me the React Hooks Rendered more hooks than during the previous render error

The second does not. When I console log the props for example I am getting them 4-5 times when the view with the first function is shown, but not the second, the second only shows 1 time in the console log.

Tried moving the setState around and logging the parents in the console but this component is the only one that's firing a bunch of times and breaking, and maybe I just dont have a firm understanding on how to structure this.

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;

Upvotes: 0

Views: 275

Answers (1)

Jacob
Jacob

Reputation: 105

Mutating the prop directly after the if statement " if (childObj.iconEl) " was causing the app to re render repeatedly.

with cloneElement I was able to have my element will have the original element’s props with the new props merged in shallowly: reactjs.org/docs/react-api.html#cloneelement the error stopped and I was able to achieve the desired result which was to change the box shadow onClick of a button that was passed down to a child element as props.

Below is the code to replace the lines after the " 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>
                                    );

Upvotes: 1

Related Questions