最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Undefined value for initial state in ReactJS - Stack Overflow

programmeradmin2浏览0评论

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

I've created a bunch of ponents which render a Bootstrap modal. Furthermore I fetch initial state parameters from the sever through the ponentDidMount function. My ponent 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 : []
            };
        },

        ponentDidMount: 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> ponent, 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 ponentWillMount 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 ponentDidMount 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?

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

I've created a bunch of ponents which render a Bootstrap modal. Furthermore I fetch initial state parameters from the sever through the ponentDidMount function. My ponent 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 : []
            };
        },

        ponentDidMount: 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> ponent, 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 ponentWillMount 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 ponentDidMount 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?

Share Improve this question edited Dec 30, 2015 at 12:59 Flo Ragossnig asked Dec 30, 2015 at 11:09 Flo RagossnigFlo Ragossnig 1,4701 gold badge20 silver badges45 bronze badges 3
  • What does this.state.data log? – Patrick Roberts Commented Dec 30, 2015 at 11:21
  • If I put console.log(this.state.data) into the render function of <L5fmModal> I get [] (0) as log output. I guess that is just the predefined empty data array. But how can I fetch data from the server and THEN render the whole application? – Flo Ragossnig Commented Dec 30, 2015 at 11:48
  • 1 @FlorianRagossnig: no need to do like that because first time it will render just UI and then call the API once API success function you have already set state again so it will again call your render function and now you have data so it will populate UI with data – Dhaval Patel Commented Dec 30, 2015 at 12:52
Add a ment  | 

2 Answers 2

Reset to default 2

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 ponent render on your browser once that done then your L5fmModal's ponentDidMount 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 ponentDidMount 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 /> ponent.

发布评论

评论列表(0)

  1. 暂无评论