0
votes

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;
1
can you add a bit more to your code snippet -> how are you rendering SimpleFormPreviewTom Finney
absolutely its not a big file so I'll insert the whole thing.Ok done....Jacob
I can't see anything immedaitely in that file that looks like it would throw that error. Are you rendering it with create element like <SimpleFormPreview ... /> because I vaguely recall it throwing that error for me once just calling the component like SimpleFormPreview(). Do you have any examples of what data you passing in for props like childAndButtonWithStylesForPreview?Tom Finney
props example= [ { "id": 0, "child": { "_id": "60143a2576ee585c52ffdfe0", "partNumber": "a", "createdBy": "Jacob1 Wazydrag", "createdOn": "2021-01-29T16:39:01.012Z", "id": "1611938341138" } } ]Jacob
how i am rendering it in parent: return <SimpleFormPreview childAndButtonWithStylesForPreview={this.props.childrenIcons} childrenToDisplay={this.props.children}/>Jacob

1 Answers

1
votes

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>
                                    );