Philip Pegden
Philip Pegden

Reputation: 2124

React error - Cannot assign to read only property 'validated' of object '#<Object>'

I have a the following component:

export const Alert = (props: {message: string, type?: AlertType, createAgainButton?: Object} ) =>
{

const type = props.type || 'Message'

switch(type)
    {
        case 'Warning':
            return (
                <div className='tgg-alert-danger'>
                    <div className='tgg-alert-icon'><Icon name='exclamation-circle'/></div>
                    <div className='tgg-alert-text'>{props.message}</div>
                </div> )
        case 'Spinner':
            return (
                <div className='tgg-alert-danger'>
                    <div className='tgg-alert-icon'><Icon name='circle-o-notch fa-spin'/></div>
                    <div className='tgg-alert-text'>{props.message}</div>
                </div>)
        default:
            return (
                <div className='tgg-alert-success'>
                    <div className='tgg-alert-icon'><Icon name='check-circle'/></div>
                    <div className='tgg-alert-text'>{props.message}</div>
                    { props.createAgainButton }
                </div>)
    }
}

For the default case, sometimes my code raises the following React error:

Cannot assign to read only property 'validated' of object '#<Object>'

The error is reported to be located in a React module:

TypeError: Cannot assign to read only property 'validated' of object '#

<Object>'
validateChildKeys
node_modules/react/cjs/react.development.js:1136
  1133 | } else if (isValidElement(node)) {
  1134 |   // This element was passed in a valid location.
  1135 |   if (node._store) {
> 1136 |     node._store.validated = true;
  1137 |   }
  1138 | } else if (node) {
  1139 |   var iteratorFn = getIteratorFn(node);

And I'm not sure why. I've tried changing the penultimate expression to :

{ props.createAgainButton && props.createAgainButton }

Here's where I use the Alert component in this case:

// @flow
import React  from 'react'
import {connect} from 'react-redux'
import {Alert} from '../../ui/coreUIComponents'
import type {AlertType} from '../misc/types'

const mapStateToProps = (state) => {
    return {
        message: state.alert.message,
        danger: state.alert.danger,
        createAgainButton: state.alert.createAgainButton
        }
}

export default connect(mapStateToProps)(

    (props: {message: string, danger: boolean, createAgainButton?: Object}) =>
    {
        window.scrollTo(0,0);                                    
        const type: AlertType = props.danger? "Warning" : "Message"

        return (
            props.message ? <div>
                { props.createAgainButton ?
                    <Alert message={props.message} type={type} createAgainButton={props.createAgainButton} />
                :
                    <Alert message={props.message} type={type}  />
                }
            </div>
            :
                <div></div>
        )
    }
)

I wonder if there is anything obvious I'm doing wrong. The alert is shown after an async call to upload data. Sometimes, it needs to show a button to create another record. The functionality is provided by a HoF that wraps underlying record components. It works for some, but not others. Any ideas?

Phil

Upvotes: 1

Views: 3103

Answers (1)

Alex
Alex

Reputation: 277

I know it's an old question, but maybe someone finds it nowadays. We had something similar happening in our codebase. I just want to mention what the cause for us was.

Briefly, there were react JSX elements stored in the state, and we were using immer which essentially deep-freezes everything in the store, thus the component._store property also got set to read only - which caused the development version of react to fail on the child-key validation step.

As I can see, you're also storing the createAgainButton somewhere, maybe it's coming from the store, where one of your middlewares could have made it immutable.

Solution: Don't store JSX in your store. If you have to, then don't use immer, but if you want to, then don't use development version of react.

Upvotes: 7

Related Questions