Nested Objects in ReactJS - javascript

I was going through the react getting started tutorial and have run into a problem with an experiment I am doing. I am able log an object but in the console, I get the following error:
Uncaught TypeError: Cannot read property 'results' of undefined
I can log the object so I know my api call is successfully but for some reason my react state does not seem to get updated. I think that my render function is happening before my data object gets updated from the API but not sure how to fix it.
http://jsfiddle.net/xJvY5/
<!doctype html>
<html>
<head>
<title>Weather Widget</title>
<link rel="stylesheet" href="weather.css" />
<script src="http://fb.me/react-0.10.0.js"></script>
<script src="http://fb.me/JSXTransformer-0.10.0.js"></script>
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
</head>
<body>
<script type="text/jsx">
/*** #jsx React.DOM */
var weatherWidget = React.createClass({
loadData: function(){
$.ajax({
url: 'http://query.yahooapis.com/v1/public/yql?q=select%20item%20from%20weather.forecast%20where%20location%3D%2222102%22&format=json',
dataType : "jsonp",
cache: false,
success: function(data) {
console.log(data)
this.setState({data: data});
}.bind(this)
});
},
getInitialState: function(){
return {data: []};
},
componentWillMount: function(){
this.loadData();
},
render: function(){
return(
<div className="ww-container">
<div className="ww-current-condition">
<div className="ww-current-temperture">{this.state.data.query.results.channel.item.condition.temp}°</div>
</div>
</div>
)
}
});
React.renderComponent(<weatherWidget />, document.body);
</script>
</body>
</html>

The problem is that React is trying to access the result of the API call while it hasn't been fetched yet. You should add null checks when accessing nested objects (this is a javascript issue rather than something React-specific).
Secondly, while the data is unavailable, your component will still try to render something. React renders your component the moment you inject it into the page, so consider showing a "loading" indicator while the API result has not been saved to state.
Here is a fork of your fiddle with appropriate null checks & "loading indicator":
http://jsfiddle.net/jxg/9WZA5/
render: function(){
var degrees = this.state.item ? this.state.item.condition.temp : 'loading...';
return(
<div className="ww-container">
<div className="ww-current-condition">
<div className="ww-current-temperture">{degrees}°</div>
</div>
</div>
);

Related

Why v-for won't render any DOMs? 'Property or method "data" is not defined on the instance but referenced during render.'

I would like to render several div containers depending on a returned API call from axios/vue. The axios call and callback work just fine, but vue won't render any divs.
Since I am using Django, I already changed the delimiters from curly brackets (which is Django default as well).
Error message in console:
Property or method "data" is not defined on the instance but referenced during render.
Make sure that this property is reactive, either in the data option,
or for class-based components, by initializing the property.
Please find a minimal code snippet as follows (if you remove the JS part the html will show up):
Thank you in advance for your help!
var app = new Vue({
delimiters: ['[[', ']]'],
el: '.EUR_Quotes',
data: {
info: []
},
created() {
axios
.get("http://data.fixer.io/api/latest?access_key=XXXd&base=EUR")
.then(response => {
this.info = response.data.rates;
console.log(response);
});
}
});
.EUR_Quotes {
font-size: 30px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<html>
<head>
</head>
<body>
<div v-for="rates in info">
<div class="EUR_Quotes">[[ data ]]
</div>
</div>
</body>
<script src="https://unpkg.com/vue#2.5.13/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</html>
You are confusing your data variable name, it should be info in your template, (not data) the actual data object is the container for all your vuejs app's data.
Check the snippet, it works fine.
var app = new Vue({
delimiters: ['[[', ']]'],
el: '.EUR_Quotes',
data: {
info: []
},
created() {
axios
.get("http://data.fixer.io/api/latest?access_key=d&base=EUR")
.then(response => {
this.info = response.data.rates;
console.log(response);
});
}
});
.EUR_Quotes {
font-size: 30px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<html>
<head>
</head>
<body>
<div v-for="rates in info">
<div class="EUR_Quotes">[[ info ]]
</div>
</div>
</body>
<script src="https://unpkg.com/vue#2.5.13/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</html>

React tutorial example throwing an error in example.js:42 [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am trying to run the example code provided in the React tutorial here:
https://facebook.github.io/react/docs/tutorial.html
I've downloaded the example code and put it in the htdocs folder of my MAMP install.
I put "http://localhost:3000/public/" into my browser and the title "Comments" and two form fields and a post button appear but no comments. I'm assuming the two comments in the json file should be appearing.
My directory structure is the same as this the git project with the php and json files in the main web folder and the html, css and javascript files in the public folder.
example.js is throwing this error at line 34
/api/comments error Not Found
I thought it might be related to ajax calls on my local machine but I've uploaded the example to a remote server and I'm getting the same error.
jquery.min.js is also throwing an error on line 4:
http://localhost:3000/api/comments?_=1456333607052 404 (Not Found)
but I'm assuming its because of an upstream error caused by example.js
Am I missing something?
Here is my index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>React Tutorial</title>
<!-- Not present in the tutorial. Just for basic styling. -->
<link rel="stylesheet" href="css/base.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.7/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.7/react-dom.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.6.15/browser.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.5/marked.min.js"></script>
</head>
<body>
<div id="content"></div>
<script type="text/babel" src="scripts/example.js"></script>
<script type="text/babel">
// To get started with this tutorial running your own code, simply remove
// the script tag loading scripts/example.js and start writing code here.
</script>
</body>
</html>
Here is my example.js
/**
* This file provided by Facebook is for non-commercial testing and evaluation
* purposes only. Facebook reserves all rights not expressly granted.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
var Comment = React.createClass({
rawMarkup: function() {
var rawMarkup = marked(this.props.children.toString(), {sanitize: true});
return { __html: rawMarkup };
},
render: function() {
return (
<div className="comment">
<h2 className="commentAuthor">
{this.props.author}
</h2>
<span dangerouslySetInnerHTML={this.rawMarkup()} />
</div>
);
}
});
var CommentBox = React.createClass({
loadCommentsFromServer: function() {
$.ajax({
url: this.props.url,
dataType: 'json',
cache: false,
success: function(data) {
this.setState({data: data});
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
handleCommentSubmit: function(comment) {
var comments = this.state.data;
// Optimistically set an id on the new comment. It will be replaced by an
// id generated by the server. In a production application you would likely
// not use Date.now() for this and would have a more robust system in place.
comment.id = Date.now();
var newComments = comments.concat([comment]);
this.setState({data: newComments});
$.ajax({
url: this.props.url,
dataType: 'json',
type: 'POST',
data: comment,
success: function(data) {
this.setState({data: data});
}.bind(this),
error: function(xhr, status, err) {
this.setState({data: comments});
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
getInitialState: function() {
return {data: []};
},
componentDidMount: function() {
this.loadCommentsFromServer();
setInterval(this.loadCommentsFromServer, this.props.pollInterval);
},
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList data={this.state.data} />
<CommentForm onCommentSubmit={this.handleCommentSubmit} />
</div>
);
}
});
var CommentList = React.createClass({
render: function() {
var commentNodes = this.props.data.map(function(comment) {
return (
<Comment author={comment.author} key={comment.id}>
{comment.text}
</Comment>
);
});
return (
<div className="commentList">
{commentNodes}
</div>
);
}
});
var CommentForm = React.createClass({
getInitialState: function() {
return {author: '', text: ''};
},
handleAuthorChange: function(e) {
this.setState({author: e.target.value});
},
handleTextChange: function(e) {
this.setState({text: e.target.value});
},
handleSubmit: function(e) {
e.preventDefault();
var author = this.state.author.trim();
var text = this.state.text.trim();
if (!text || !author) {
return;
}
this.props.onCommentSubmit({author: author, text: text});
this.setState({author: '', text: ''});
},
render: function() {
return (
<form className="commentForm" onSubmit={this.handleSubmit}>
<input
type="text"
placeholder="Your name"
value={this.state.author}
onChange={this.handleAuthorChange}
/>
<input
type="text"
placeholder="Say something..."
value={this.state.text}
onChange={this.handleTextChange}
/>
<input type="submit" value="Post" />
</form>
);
}
});
ReactDOM.render(
<CommentBox url="/api/comments" pollInterval={2000} />,
document.getElementById('content')
);
The example servers supplied (See the README.md of the tutorial) have configuration to route the "/api/comments" url, which your standalone servers won't have configured. Either add that to your server or, simpler, just use one of the example server scripts.
You need to read the README file incuded with the tutorial code. You need to run their server implementation to provide the /api/comments endpoint.

React Uncaught TypeError: this.setState is not a function

This is my first React code. I am trying to call a Restful web services from React.
It kept saying "Uncaught TypeError: this.setState is not a function". I couldn't figure out what's wrong with the code.
<!DOCTYPE html>
<html>
<head>
<title>React Flux</title>
<script src="https://fb.me/react-0.13.3.js"></script>
<script src="https://fb.me/JSXTransformer-0.13.3.js"></script>
<script src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
</head>
<body>
<div id="component"></div>
<script type="text/jsx">
var JavaEEWSTest = React.createClass({
getInitialState: function () {
return {text: ''};
},
componentDidMount: function(){
$.ajax({
url: "http://localhost:8080/rest/user/456"
}).then(function(data) {
this.setState({text: data.name});
}).bind(this)
},
render: function() {
return <div>Response - {this.state.text}</div>;
}
});
React.render(<JavaEEWSTest />, document.getElementById('component'));
</script>
</body>
</html>
You need set this to callback function
$.ajax({
url: "http://localhost:8080/rest/user/456"
}).then(function(data) {
this.setState({text: data.name});
}.bind(this))
^^^^^^^^^^^
but not for $.ajax/then - }).bind(this)

Windows App Development - ListView retrieving data

I am new to Windows App Development and I am trying to create a ListView in order to understand how it works. My problem is that I am trying to use a namespace on my ListView div and it returns the error saying that the property dataSource doesn't exist.
This is my html and javascript:
// For an introduction to the Page Control template, see the following documentation:
// http://go.microsoft.com/fwlink/?LinkId=232511
(function () {
"use strict";
WinJS.UI.Pages.define("/pages/episodes/episodes.html", {
// This function is called whenever a user navigates to this page. It
// populates the page elements with the app's data.
ready: function (element, options) {
// TODO: Initialize the page here.
Episodes.Data.assignItems(items);
WinJS.UI.processAll();
},
unload: function () {
// TODO: Respond to navigations away from this page.
},
updateLayout: function (element) {
/// <param name="element" domElement="true" />
// TODO: Respond to changes in layout.
},
});
WinJS.Namespace.define("Episodes.Data", {
itemsBindingList: undefined,
assignItems: function (items) {
Episodes.Data.itemsBindingList = new WinJS.Binding.List(items);
},
});
var items = [
{ title: 'Air Gear' },
{ title: 'Bakuman' }
];
})();
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>episodes</title>
<link href="episodes.css" rel="stylesheet" />
<script src="episodes.js"></script>
</head>
<body>
<div class="episodes fragment">
<header class="page-header" aria-label="Header content" role="banner">
<button class="back-button" data-win-control="WinJS.UI.BackButton"></button>
<h1 class="titlearea win-type-ellipsis">
<span class="pagetitle">Welcome to episodes</span>
</h1>
</header>
<section class="page-section" aria-label="Main content" role="main">
<div data-win-control="WinJS.UI.ListView" data-win-options="{
itemDataSource : Episodes.Data.itemsBindingList.dataSource
}"></div>
</section>
</div>
</body>
</html>
Since I am using an anonymous function on my .js file, I created a namespace that I can use on the .html file. Inside the ListView div, I have this:
div data-win-control="WinJS.UI.ListView" data-win-options="{
itemDataSource : Episodes.Data.itemsBindingList.dataSource
}"></div>
I am using the namespace to retrieve my data that I want to show on the ListView. My problem is that I get an error saying:
"{\"exception\":null,\"error\":{\"description\":\"It's not possible to obtain the property 'dataSource' of undifined or null reference\"
From what I can tell it is the fact that your property is initially undefined:
WinJS.Namespace.define("Episodes.Data", {
itemsBindingList: undefined, //this is a problem
assignItems: function (items) {
Episodes.Data.itemsBindingList = new WinJS.Binding.List(items);
},
});
Your html is then trying to bind to a property of an undefined object:
<section class="page-section" aria-label="Main content" role="main">
<div data-win-control="WinJS.UI.ListView" data-win-options="{
itemDataSource : Episodes.Data.itemsBindingList.dataSource
}"></div>
</section>
Either try using an empty array to initialize:
WinJS.Namespace.define("Episodes.Data", {
itemsBindingList: new WinJS.Binding.List([]),
assignItems: function (items) {
Episodes.Data.itemsBindingList = new WinJS.Binding.List(items);
},
});
Or you can set the datasource in your code:
ready: function (element, options) {
// TODO: Initialize the page here.
var listView = document.getElementById('myListView').winControl;
Episodes.Data.assignItems(items);
listView.data = Episodes.Data.itemsBindingList;
WinJS.UI.processAll();
},
You can verify this by debugging in the ready function and your exception should come before your breakpoint gets hit.

How to access nested object in React js 0.13.3

The below added code is working fine in React js 0.10.0. I wanna run same code in 0.13.0 version also. My main requirement is accessing nested object as default object like "this.state.data.query.results.channel.item.condition.temp".
<!doctype html>
<html>
<head>
<title>Weather Widget</title>
<link rel="stylesheet" href="weather.css" />
<script src="http://fb.me/react-0.10.0.js"></script>
<script src="http://fb.me/JSXTransformer-0.10.0.js"></script>
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
</head>
<body>
<script type="text/jsx">
/*** #jsx React.DOM */
var weatherWidget = React.createClass({
loadData: function(){
$.ajax({
url: 'http://query.yahooapis.com/v1/public/yql?q=select%20item%20from%20weather.forecast%20where%20location%3D%2222102%22&format=json',
dataType : "jsonp",
cache: false,
success: function(data) {
console.log(data)
this.setState({data: data});
}.bind(this)
});
},
getInitialState: function(){
return {data: []};
},
componentWillMount: function(){
this.loadData();
},
render: function(){
return(
<div className="ww-container">
<div className="ww-current-condition">
<div className="ww-current-temperture">{this.state.data.query.results.channel.item.condition.temp}°</div>
</div>
</div>
)
}
});
React.renderComponent(<weatherWidget />, document.body);
</script>
</body>
</html>
http://jsfiddle.net/xJvY5/
You should set initial state, like so
getInitialState: function(){
return {
data: {
query: {
results: {
channel: {item: {condition: {temp: 0}}}
}
}
}
};
},
Example - (v 0.10.0)
Example - (v 0.13.3) - Note - that in version 0.13.3 you should use .render method instead of .renderComponent
or you can check data in render method, if data is undefined - show loading...., if state was updated you will see your data
getInitialState: function(){
return {};
},
render: function() {
if (!this.state.data) {
return <div>Loading...</div>;
}
....
}
Example - (v 0.13.3)

Categories