简体   繁体   中英

Undefined value for initial state in ReactJS

I'm still pretty new with ReactJS and now I ran into something which confuses me totally.

I've created a bunch of components which render a Bootstrap modal. Furthermore I fetch initial state parameters from the sever through the componentDidMount function. My component structure looks something like this:

<App>
  <Modal Lauch Button /> 

  <Modal>
   <Modal Header />
   <Modal Body />     <-- here's the problem
  </Modal>
</App>

and my initial state array is of the form (of course JSON encoded):

array:5 [▼
   ...
   ...
   "private" => true
   "files" => array:2 [▼
       1 => array:7 [▼
          "id" => 0
          "route" => "some route"
          ...
          ...
       ]
       2 => array:7 [▼
          "id" => 1
          "route" => "some other route"
          ...
          ...
       ]
   ]
]

and my (minified) React application like this:

<script type="text/babel">

    var L5fmModalBody = React.createClass({

        render: function() {

            return(
                <Modal.Body>
                    <Grid fluid={true}>
                        <Row>
                            {
                                this.props.files.map(function (file) {
                                    return <L5fmModalBodyFileContent id={file.id} route = {file.route} / >
                                })
                            }
                        </Row>
                    </Grid>
                </Modal.Body>
            );
        }

    });

    var L5fmModalBodyFileContent = React.createClass({

        render : function() {
            return(
                <Col xs={6} md={4} className="img-row">
                    <div className="thumbnail thumbnail-img">
                        <img key={this.props.id} src={this.props.route} />
                    </div>
                </Col>
            );
        }

    });

    var L5fmModal = React.createClass({

        getInitialState : function() {
            return {
                data : []
            };
        },

        componentDidMount: function() {
            $.ajax({
                url: 'L5fm/setInitialState',
                dataType: 'json',
                cache: false,
                success: function(data) {
                    this.setState({data: data});
                    console.log(data);
                    console.log(this.state.data);
                }.bind(this),
                error: function(xhr, status, err) {
                    console.error(this.props.url, status, err.toString());
                }.bind(this)
            });
        },

        render: function() {

            return(

                <Modal {...this.props} bsSize="large" aria-labelledby="contained-modal-title-lg">
                    <Modal.Header closeButton>
                        <div className="header-button-group">
                            some buttons
                        </div>
                    </Modal.Header>

                    <L5fmModalBody files={this.state.data.files} />
                </Modal>
            );
        }

    });


    var App = React.createClass({
        getInitialState: function() {
            return { lgShow: false };
        },
        render: function() {
            let lgClose = () => this.setState({ lgShow: false });

            return (
                 <Button bsStyle="primary" onClick={()=>this.setState({ lgShow: true })}>
                    Launch large demo modal
                 </Button>
                 <L5fmModal show={this.state.lgShow} onHide={lgClose} />
            );
        }
    });

    ReactDOM.render(<App />, document.getElementById("modal"));

</script>

Whenever I run the application I get following error:

L5fmModalBody_renderTypeError: this.props.files.map is not a function. (In 'this.props.files.map', 'this.props.files.map' is undefined)

If I console.log(this.state.data.files) in my <Modal> component, it also shows that this.state.data.files is undefined? Obviously I have not understood what is going on. I've also tried to fetch data with componentWillMount but this did not help either. What am I doing wrong?

Thanks!


UPDATE

I think I got a step further. The actual issue is not that this.set,state is null at the start, because after componentDidMount is called and the "new" states are set, the UI gets rendered again. Furthermore I found out that JSON apparently handles assoziative arrays as objects and I believe that I can't call map on an object.

Any ideas?

yes of course it will throw error because you are passing this <L5fmModalBody files={this.state.data.files} /> and your state it's declare in data : [] that means when first render happen data is just a blank array and your component render on your browser once that done then your L5fmModal's componentDidMount called and it will fetch the data from DB and again update state and render function called and data have a file field but what about very first load when your array is just an empty at that time file field is undefined so you have to implement below mentioned code in your L5fmModalBody

     {
(type of this.props.files != 'undefined')? this.props.files.map(function (file) {
                                        return <L5fmModalBodyFileContent id={file.id} route = {file.route} / >
                                    }):null                                
}

or you can also prevent from your L5fmModal it self using

{this.state.data.length>0 ? <L5fmModalBody files={this.state.data.files} />:null}

Thanks to Dhaval Patel I finally have the answer to this issue. The problem was not the null value of the initial state because when componentDidMount gets called the UI gets rendered again and receives the updated states from the server. The actual problem was that JSON treats associative arrays as objects and therefore I could not call a simple map .

I just changed

{
    this.props.files.map(function (file) {
        return <L5fmModalBodyFileContent id={file.id} route = {file.route} / >
    })
}

to

{
    Object.keys(object).map(
        function(d){
            return <L5fmModalBodyFileContent id={object[d].id} route={object[d].route} />
    })
}

where object = this.props.files and it works like a charm!

To avoid the error of the (at first) undefined object I've used

{this.state.data.length!=0 ? <L5fmModalBody files={this.state.data.files} />:null}

in the <Modal /> component.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM