I am trying to implement a component which handles ajax requests to the server and passes data to two child components. However it appears the ajax calls are never being made.
Feed.js:237 Uncaught TypeError: Cannot read property 'data' of null
is the error I'm getting.
// Parent component containting feed and friends components,
// handles retrieving data for both
import React, { Component } from 'react'
import FeedBox from './Feed.js'
import FriendsBox from './Friends'
const config = require('../../config')
export default class FrontPage extends Component {
constructor(props) {
super(props)
this.state = {
data: {},
pollInterval: config.pollInterval
}
this.loadDataFromServer = this.loadDataFromServer.bind(this)
}
loadDataFromServer() {
$ajax({
url: config.apiUrl + 'frontpage',
dataType: 'jsonp',
cache: false,
success: (data) => {
this.setState({data: data})
console.log(data)
},
error: (xhr, status, err) => {
console.error(this.url, status, error.toString())
}
})
}
componentDidMount() {
this.loadDataFromServer()
setInterval(this.loadDataFromServer, this.state.pollInterval)
}
componentWillUnmount() {
this.state.pollInterval = false
}
render() {
return (
<div className="FrontPage">
<FeedBox data={ this.state.data.feedData } />
<FriendsBox data={ this.state.data.friendsData } />
</div>
)
}
}
EDIT:
Here is the code for the Feed component, one of the two child components of FrontPage which is being passed props from its parent
import React, { Component } from 'react';
var config = require('../../config')
class Thread extends Component {
rawMarkup() {
var rawMarkup = marked(this.props.children.toString(), { sanitize: true })
return {__html: rawMarkup }
}
render() {
return (
<div className="thread">
<h4 className="threadVictim">Dear {this.props.victim}: </h4>
<span dangerouslySetInnerHTML={this.rawMarkup()} />
<p>signed,</p>
<div>{this.props.author} and {this.props.ct} others.</div>
<hr></hr>
</div>
)
}
}
class ThreadList extends Component {
render() {
var threadNodes = this.props.data.map(function (thread) {
return (
<Thread victim={ thread.victim } author={ thread.author } ct={ thread.included.length } key={ thread._id }>
{ thread.text }
</Thread>
)
})
return (
<div className="threadList">
{ threadNodes }
</div>
)
}
}
var ThreadForm = React.createClass({
getInitialState: function () {
return {author: '',
text: '',
included: '',
victim: '',
ct: ''
}
},
handleAuthorChange: function (e) {
this.setState({author: e.target.value})
},
handleTextChange: function (e) {
this.setState({text: e.target.value})
},
handleIncludedChange: function (e) {
this.setState({included: e.target.value})
},
handleVictimChange: function (e) {
this.setState({victim: e.target.value})
},
handleSubmit: function (e) {
e.preventDefault()
var author = this.state.author.trim()
var text = this.state.text.trim()
var included = this.state.included.trim()
var victim = this.state.victim.trim()
if (!text || !author || !included || !victim) {
return
}
this.props.onThreadSubmit({author: author,
text: text,
included: included,
victim: victim
})
this.setState({author: '',
text: '',
included: '',
victim: '',
})
},
render: function () {
return (
<form className="threadForm" 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="text"
placeholder="Name your victim"
value={this.state.victim}
onChange={this.handleVictimChange} />
<input
type="text"
placeholder="Who can see?"
value={this.state.included}
onChange={this.handleIncludedChange} />
<input type="submit" value="Post" />
</form>
)
}
})
var ThreadsBox = React.createClass({
// loadThreadsFromServer: function () {
// $.ajax({
// url: config.apiUrl + 'feed',
// dataType: 'jsonp',
// cache: false,
// success: function (data) {
// this.setState({data: data})
// }.bind(this),
// error: function (xhr, status, err) {
// console.error(this.url, status, err.toString())
// }.bind(this)
// })
// },
handleThreadSubmit: function (thread) {
var threads = this.state.data
var newThreads = threads.concat([thread])
this.setState({data: newThreads})
$.ajax({
url: config.apiUrl + 'threads',
dataType: 'json',
type: 'POST',
data: thread,
success: function (data) {
this.setState({data: data})
}.bind(this),
error: function (xhr, status, err) {
this.setState({data: threads})
console.error(this.url, status, err.toString())
}.bind(this)
})
},
// getInitialState: function () {
// return {data: [],
// pollInterval: config.pollInterval}
// },
// componentDidMount: function () {
// this.loadThreadsFromServer()
// setInterval(this.loadThreadsFromServer, this.state.pollInterval)
// },
// componentWillUnmount: function () {
// this.state.pollInterval = false;
// },
render: function () {
return (
<div className="threadsBox">
<div className="feedNav">
<h1>Home</h1>
<h1>Heat</h1>
</div>
<ThreadList data={ this.state.data } />
<ThreadForm onThreadSubmit={ this.handleThreadSubmit } />
</div>
)
}
})
module.exports = ThreadsBox
You need to define the initial state object in ThreadsBox so it is not null:
var ThreadsBox = React.createClass({
getInitialState: function() {
return {
data: {}
};
}
// ...
})
module.exports = ThreadsBox
the ajax call is not firing. try adding the method for the request: GET or POST.
Related
I am trying to create two components, one that holds the results of an API call from iTunes. I want to be able to click on any one of the items and move it to the empty component, moveResults, and then move it back to searchResults if it is clicked again. From other exercises, I feel like I am close, however I keep getting an error about the this.handleEvent = this.handleEvent.bind(this). Any ideas as to where I might have gone wrong and some possible solutions?
var App = React.createClass({
getInitialState: function() {
return {
searchResults: [],
moveResults: []
}
},
this.handleEvent = this.handleEvent.bind(this);
showResults: function(response) {
this.setState({
searchResults: response.results,
moveResults: []
})
},
search: function(URL) {
$.ajax({
type: 'GET',
dataType: 'json',
url: URL,
success: function(response) {
this.showResults(response);
}.bind(this)
});
},
handleEvent(trackId) {
const isInSearchResults = this.state.searchResults.includes(trackId);
this.setState({
searchResults: isInSearchResults ? this.state.searchResults.filter(i => i !== trackId) : [...this.state.searchResults, trackId],
moveResults: isInSearchResults ? [...this.state.moveResults, trackId] : this.state.moveResults.filter(i => i !== trackId)
});
},
componentDidMount() {
this.search('https://itunes.apple.com/search?term=broods')
},
render: function(){
return (
<div>
<Results searchResults={this.state.searchResults} handleEvent={this.handleEvent}/>
<Results searchResults={this.state.moveResults} handleEvent={this.handleEvent} />
</div>
);
}
});
var Results = React.createClass({
render: function(){
let handleEvent = this.props.handleEvent;
var resultItems = this.props.searchResults.map(function(result) {
return <ResultItem key={result.trackId} trackName={result.trackName} onClick={() => handleEvent(resultItems.id)} />
});
return(
<ul>
{resultItems}
</ul>
);
}
});
var ResultItem = React.createClass({
render: function(){
return <li> {this.props.trackName} </li>;
}
});
ReactDOM.render(
<App />, document.getElementById('root')
);
I'm trying to build a basic chat app using React and Socket.Io based on the React tutorial https://facebook.github.io/react/docs/tutorial.html but keep getting an error "Cannot read property 'emit' of undefined". It's probably something trivial that I overlooked but I can't figure it out.
The function that triggers the error is:
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: '' });
this.socket.emit('message', comment);
},
The full code is
import React, { Component, PropTypes } from 'react';
import ReactDom from 'react-dom';
import io from 'socket.io-client'
/********************************************************************************************************/
var CommentBox = React.createClass({
getInitialState: function () {
return { data: [] };
},
handleCommentSubmit: function (comment) {
this.setState({ data: [comment, ...this.state.data] });
},
componentDidMount: function (data) {
this.socket = io.connect();
this.socket.on('message', function (comment) {
this.setState({ data: [comment, ...this.state.data] });
});
},
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: '' });
this.socket.emit('message', comment);
},
render: function () {
return (
<div>
<form className='commentForm' onSubmit={this.handleSubmit}>
<input type='text' placeholder='Name' value={this.state.author} onChange={this.handleAuthorChange} />
<input type='text' placeholder='Enter Message' value={this.state.text} onChange={this.handleTextChange} />
<input type='submit' value='Post' />
</form>
</div>
);
}
});
/********************************************************************************************************/
var Comment = React.createClass({
render: function () {
return (
<div className="comment">
<h2 className="commentAuthor">
{this.props.author}
</h2>
{this.props.children}
</div>
);
}
});
/********************************************************************************************************/
ReactDom.render(
<CommentBox />,
document.getElementById('container')
);
The call to this.socket.emit('message', comment) is at the wrong place neither this.socket nor comment is defined in your CommentForm Component.
You have to call this.socket.emit('message', comment) in the handleCommentSubmit Method in the CommentBox Component. (Line 14 in the second code example)
I'm not sure why i'm getting this error, i've modified the code from the tutorial so that this.setState({data: data}); becomes this.setState({data: data.datalist});to reflect the response from the backend. I've made the changes to my code according to this answer but the same error persists React JS - Uncaught TypeError: this.props.data.map is not a function.
Sample code from tutorial configured to fetch JSON from my backend:
import React from 'react'
import ReactDOM from 'react-dom'
import $ from 'jquery'
var Comment = React.createClass({
rawMarkup: function() {
var md = new Remarkable();
var rawMarkup = md.render(this.props.children.toString());
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({cache:false});
$.ajax({
url: this.props.url,
dataType: 'json',
success: function(data) {
console.log(data.datalist);
this.setState({data: data.datalist});
}.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;
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="/core/get_json" pollInterval={2000} />,
document.getElementById('app')
);
JSON from backend(django):
def get_json(request):
return JsonResponse({'datalist': [
{'id': 1, 'author': "Pete Hunt", 'text': "This is one comment"},
{'id': 2, 'author': "Jordan Walke", 'text': "This is *another* comment"}
]})
Browser getting said JSON under network response:
{"datalist": [{"id": 1, "author": "Pete Hunt", "text": "This is one comment"}, {"id": 2, "author": "Jordan Walke", "text": "This is *another* comment"}]}
Render calls this.props.data right away, your data might not have arrive yet, so you need to check if data is ready, by doing this this.props.data && this.props.data.map.
var commentNodes = this.props.data && this.props.data.map(function(comment)
{
return (
<Comment author={comment.author} key={comment.id}>
{comment.text}
</Comment>
);
});
map function is being called two times, once before the request and one time after. To correct this you can use
{this.props.data.length > 0 && this.props.data.map()}
This would do the trick.
I am checking the login via jquery using this methods:
module.exports = {
login: function(username, pass, cb) {
if (localStorage.token) {
if (cb) cb(true)
return
}
this.getToken(username, pass, (res) => {
if (res.authenticated) {
localStorage.token = res.token
if (cb) cb(true)
} else {
if (cb) cb(false)
}
})
},
logout: function() {
delete localStorage.token
},
loggedIn: function() {
return !!localStorage.token
},
getToken: function(username, pass, cb) {
$.ajax({
type: 'POST',
url: '/obtain-auth-token/',
data: {
email_or_username: username,
password: pass
},
success: function(res){
cb({
authenticated: true,
token: res.token
})
}
})
},
}
My login validation is working correctly, if the user and password are correct it redirects to app page. But if is incorrect I receive this message at terminal:
POST http://url_base/obtain-auth-token/ 400 (Bad Request)
and this element:
<p>Bad login information</p>
Does not appears at my login page.
I think that the problem is this error from jQuery but I don't know how to solve this.
I am using this repository how reference: https://github.com/reactjs/react-router/blob/master/examples/auth-flow/auth.js
Here is my LoginPage:
'use strict'
import React from 'react'
import { Router, browserHistory } from 'react-router'
import '../../../css/login.css'
import '../../../css/animation.css'
import Logo from '../icons/Logo'
import auth from './auth'
class LoginPage extends React.Component{
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.state = {
error: false,
loggedIn: auth.loggedIn()
}
}
handleSubmit(ev) {
ev.preventDefault()
var username = this.refs.username.value
var pass = this.refs.pass.value
auth.login(username, pass, (loggedIn) => {
if (loggedIn) {
const { location } = this.props
if (location.state && location.state.nextPathname) {
browserHistory.push(location.state.nextPathname)
} else {
browserHistory.push('app')
}
}
else{
this.setState({error:true});
}
})
}
render() {
return (
<div id="login" className="login">
<div className="login-content">
<div id="login-content-container" className="login-content-container">
<Logo svgClass="login-content-container-logo" width="270" height="35"/>
<form className="login-content-container-form" onSubmit={this.handleSubmit}>
<input className="login-content-container-form-input" type="text" ref="username" placeholder="username"/>
<input className="login-content-container-form-input" type="password" ref="pass" placeholder="password"/>
<button className="login-content-container-form-button">login</button>
</form>
{this.state.error && (
<p>Bad login information</p>
)}
</div>
</div>
</div>
);
}
}
export default LoginPage
It simply because you haven't handled the ajax error callback in getToken
getToken: function(username, pass, cb) {
$.ajax({
type: 'POST',
url: '/obtain-auth-token/',
data: {
email_or_username: username,
password: pass
},
success: function(res){
cb({
authenticated: true,
token: res.token
})
},
error: function () { cb({authenticated: false}); }
})
},
I am trying to show data from package.json in my ReactJS components. I have seen many answers on SO and tried to implement it. It is neither showing any data nor an error.
This is package.json:
{
"name":"Clark Kent",
"job":"Superman"
}
This is my jsx:
var App = React.createClass({
getInitialState: function(){
return { myData: [] };
},
showResults: function(response){
this.setState({
myData: response
});
},
loadData: function(URL) {
var that = this;
$.ajax({
type: 'GET',
dataType: 'jsonp',
url: URL,
success: function(response){
that.showResults(response);
}
})
},
componentDidMount: function() {
this.loadData("package.json");
},
render: function(){
return(
<div>
<Component1 data={this.state.myData} />
<Component2 data={this.state.myData}/>
</div>
)
}
});
var Component1 = React.createClass({
render: function () {
return(
<div>Name: {this.props.data.name}</div>
)
}
});
var Component2 = React.createClass({
render: function () {
return(
<div>Job: {this.props.data.job}</div>
)
}
});
ReactDOM.render(<App/>, document.getElementById('container'));